LCOV - code coverage report
Current view: top level - src/script/lua_api - l_inventory.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 316 0.3 %
Date: 2015-07-11 18:23:49 Functions: 2 32 6.2 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "lua_api/l_inventory.h"
      21             : #include "lua_api/l_internal.h"
      22             : #include "lua_api/l_item.h"
      23             : #include "common/c_converter.h"
      24             : #include "common/c_content.h"
      25             : #include "server.h"
      26             : #include "player.h"
      27             : 
      28             : /*
      29             :         InvRef
      30             : */
      31           0 : InvRef* InvRef::checkobject(lua_State *L, int narg)
      32             : {
      33           0 :         luaL_checktype(L, narg, LUA_TUSERDATA);
      34           0 :         void *ud = luaL_checkudata(L, narg, className);
      35           0 :         if(!ud) luaL_typerror(L, narg, className);
      36           0 :         return *(InvRef**)ud;  // unbox pointer
      37             : }
      38             : 
      39           0 : Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
      40             : {
      41           0 :         return getServer(L)->getInventory(ref->m_loc);
      42             : }
      43             : 
      44           0 : InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
      45             :                 const char *listname)
      46             : {
      47           0 :         NO_MAP_LOCK_REQUIRED;
      48           0 :         Inventory *inv = getinv(L, ref);
      49           0 :         if(!inv)
      50           0 :                 return NULL;
      51           0 :         return inv->getList(listname);
      52             : }
      53             : 
      54           0 : void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
      55             : {
      56             :         // Inform other things that the inventory has changed
      57           0 :         getServer(L)->setInventoryModified(ref->m_loc);
      58           0 : }
      59             : 
      60             : // Exported functions
      61             : 
      62             : // garbage collector
      63           0 : int InvRef::gc_object(lua_State *L) {
      64           0 :         InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
      65           0 :         delete o;
      66           0 :         return 0;
      67             : }
      68             : 
      69             : // is_empty(self, listname) -> true/false
      70           0 : int InvRef::l_is_empty(lua_State *L)
      71             : {
      72           0 :         NO_MAP_LOCK_REQUIRED;
      73           0 :         InvRef *ref = checkobject(L, 1);
      74           0 :         const char *listname = luaL_checkstring(L, 2);
      75           0 :         InventoryList *list = getlist(L, ref, listname);
      76           0 :         if(list && list->getUsedSlots() > 0){
      77           0 :                 lua_pushboolean(L, false);
      78             :         } else {
      79           0 :                 lua_pushboolean(L, true);
      80             :         }
      81           0 :         return 1;
      82             : }
      83             : 
      84             : // get_size(self, listname)
      85           0 : int InvRef::l_get_size(lua_State *L)
      86             : {
      87           0 :         NO_MAP_LOCK_REQUIRED;
      88           0 :         InvRef *ref = checkobject(L, 1);
      89           0 :         const char *listname = luaL_checkstring(L, 2);
      90           0 :         InventoryList *list = getlist(L, ref, listname);
      91           0 :         if(list){
      92           0 :                 lua_pushinteger(L, list->getSize());
      93             :         } else {
      94           0 :                 lua_pushinteger(L, 0);
      95             :         }
      96           0 :         return 1;
      97             : }
      98             : 
      99             : // get_width(self, listname)
     100           0 : int InvRef::l_get_width(lua_State *L)
     101             : {
     102           0 :         NO_MAP_LOCK_REQUIRED;
     103           0 :         InvRef *ref = checkobject(L, 1);
     104           0 :         const char *listname = luaL_checkstring(L, 2);
     105           0 :         InventoryList *list = getlist(L, ref, listname);
     106           0 :         if(list){
     107           0 :                 lua_pushinteger(L, list->getWidth());
     108             :         } else {
     109           0 :                 lua_pushinteger(L, 0);
     110             :         }
     111           0 :         return 1;
     112             : }
     113             : 
     114             : // set_size(self, listname, size)
     115           0 : int InvRef::l_set_size(lua_State *L)
     116             : {
     117           0 :         NO_MAP_LOCK_REQUIRED;
     118           0 :         InvRef *ref = checkobject(L, 1);
     119           0 :         const char *listname = luaL_checkstring(L, 2);
     120             : 
     121           0 :         int newsize = luaL_checknumber(L, 3);
     122           0 :         if (newsize < 0) {
     123           0 :                 lua_pushboolean(L, false);
     124           0 :                 return 1;
     125             :         }
     126             : 
     127           0 :         Inventory *inv = getinv(L, ref);
     128           0 :         if(inv == NULL){
     129           0 :                 lua_pushboolean(L, false);
     130           0 :                 return 1;
     131             :         }
     132           0 :         if(newsize == 0){
     133           0 :                 inv->deleteList(listname);
     134           0 :                 reportInventoryChange(L, ref);
     135           0 :                 lua_pushboolean(L, true);
     136           0 :                 return 1;
     137             :         }
     138           0 :         InventoryList *list = inv->getList(listname);
     139           0 :         if(list){
     140           0 :                 list->setSize(newsize);
     141             :         } else {
     142           0 :                 list = inv->addList(listname, newsize);
     143           0 :                 if (!list)
     144             :                 {
     145           0 :                         lua_pushboolean(L, false);
     146           0 :                         return 1;
     147             :                 }
     148             :         }
     149           0 :         reportInventoryChange(L, ref);
     150           0 :         lua_pushboolean(L, true);
     151           0 :         return 1;
     152             : }
     153             : 
     154             : // set_width(self, listname, size)
     155           0 : int InvRef::l_set_width(lua_State *L)
     156             : {
     157           0 :         NO_MAP_LOCK_REQUIRED;
     158           0 :         InvRef *ref = checkobject(L, 1);
     159           0 :         const char *listname = luaL_checkstring(L, 2);
     160           0 :         int newwidth = luaL_checknumber(L, 3);
     161           0 :         Inventory *inv = getinv(L, ref);
     162           0 :         if(inv == NULL){
     163           0 :                 return 0;
     164             :         }
     165           0 :         InventoryList *list = inv->getList(listname);
     166           0 :         if(list){
     167           0 :                 list->setWidth(newwidth);
     168             :         } else {
     169           0 :                 return 0;
     170             :         }
     171           0 :         reportInventoryChange(L, ref);
     172           0 :         return 0;
     173             : }
     174             : 
     175             : // get_stack(self, listname, i) -> itemstack
     176           0 : int InvRef::l_get_stack(lua_State *L)
     177             : {
     178           0 :         NO_MAP_LOCK_REQUIRED;
     179           0 :         InvRef *ref = checkobject(L, 1);
     180           0 :         const char *listname = luaL_checkstring(L, 2);
     181           0 :         int i = luaL_checknumber(L, 3) - 1;
     182           0 :         InventoryList *list = getlist(L, ref, listname);
     183           0 :         ItemStack item;
     184           0 :         if(list != NULL && i >= 0 && i < (int) list->getSize())
     185           0 :                 item = list->getItem(i);
     186           0 :         LuaItemStack::create(L, item);
     187           0 :         return 1;
     188             : }
     189             : 
     190             : // set_stack(self, listname, i, stack) -> true/false
     191           0 : int InvRef::l_set_stack(lua_State *L)
     192             : {
     193           0 :         NO_MAP_LOCK_REQUIRED;
     194           0 :         InvRef *ref = checkobject(L, 1);
     195           0 :         const char *listname = luaL_checkstring(L, 2);
     196           0 :         int i = luaL_checknumber(L, 3) - 1;
     197           0 :         ItemStack newitem = read_item(L, 4, getServer(L));
     198           0 :         InventoryList *list = getlist(L, ref, listname);
     199           0 :         if(list != NULL && i >= 0 && i < (int) list->getSize()){
     200           0 :                 list->changeItem(i, newitem);
     201           0 :                 reportInventoryChange(L, ref);
     202           0 :                 lua_pushboolean(L, true);
     203             :         } else {
     204           0 :                 lua_pushboolean(L, false);
     205             :         }
     206           0 :         return 1;
     207             : }
     208             : 
     209             : // get_list(self, listname) -> list or nil
     210           0 : int InvRef::l_get_list(lua_State *L)
     211             : {
     212           0 :         NO_MAP_LOCK_REQUIRED;
     213           0 :         InvRef *ref = checkobject(L, 1);
     214           0 :         const char *listname = luaL_checkstring(L, 2);
     215           0 :         Inventory *inv = getinv(L, ref);
     216           0 :         if(inv){
     217           0 :                 push_inventory_list(L, inv, listname);
     218             :         } else {
     219           0 :                 lua_pushnil(L);
     220             :         }
     221           0 :         return 1;
     222             : }
     223             : 
     224             : // set_list(self, listname, list)
     225           0 : int InvRef::l_set_list(lua_State *L)
     226             : {
     227           0 :         NO_MAP_LOCK_REQUIRED;
     228           0 :         InvRef *ref = checkobject(L, 1);
     229           0 :         const char *listname = luaL_checkstring(L, 2);
     230           0 :         Inventory *inv = getinv(L, ref);
     231           0 :         if(inv == NULL){
     232           0 :                 return 0;
     233             :         }
     234           0 :         InventoryList *list = inv->getList(listname);
     235           0 :         if(list)
     236           0 :                 read_inventory_list(L, 3, inv, listname,
     237           0 :                                 getServer(L), list->getSize());
     238             :         else
     239           0 :                 read_inventory_list(L, 3, inv, listname, getServer(L));
     240           0 :         reportInventoryChange(L, ref);
     241           0 :         return 0;
     242             : }
     243             : 
     244             : // get_lists(self) -> list of InventoryLists
     245           0 : int InvRef::l_get_lists(lua_State *L)
     246             : {
     247           0 :         NO_MAP_LOCK_REQUIRED;
     248           0 :         InvRef *ref = checkobject(L, 1);
     249           0 :         Inventory *inv = getinv(L, ref);
     250           0 :         if (!inv) {
     251           0 :                 return 0;
     252             :         }
     253           0 :         std::vector<const InventoryList*> lists = inv->getLists();
     254           0 :         std::vector<const InventoryList*>::iterator iter = lists.begin();
     255           0 :         lua_createtable(L, 0, lists.size());
     256           0 :         for (; iter != lists.end(); iter++) {
     257           0 :                 const char* name = (*iter)->getName().c_str();
     258           0 :                 lua_pushstring(L, name);
     259           0 :                 push_inventory_list(L, inv, name);
     260           0 :                 lua_rawset(L, -3);
     261             :         }
     262           0 :         return 1;
     263             : }
     264             : 
     265             : // set_lists(self, lists)
     266           0 : int InvRef::l_set_lists(lua_State *L)
     267             : {
     268           0 :         NO_MAP_LOCK_REQUIRED;
     269           0 :         InvRef *ref = checkobject(L, 1);
     270           0 :         Inventory *inv = getinv(L, ref);
     271           0 :         if (!inv) {
     272           0 :                 return 0;
     273             :         }
     274             : 
     275             :         // Make a temporary inventory in case reading fails
     276           0 :         Inventory *tempInv(inv);
     277           0 :         tempInv->clear();
     278             : 
     279           0 :         Server *server = getServer(L);
     280             : 
     281           0 :         lua_pushnil(L);
     282           0 :         while (lua_next(L, 2)) {
     283           0 :                 const char *listname = lua_tostring(L, -2);
     284           0 :                 read_inventory_list(L, -1, tempInv, listname, server);
     285           0 :                 lua_pop(L, 1);
     286             :         }
     287           0 :         inv = tempInv;
     288           0 :         return 0;
     289             : }
     290             : 
     291             : // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
     292             : // Returns the leftover stack
     293           0 : int InvRef::l_add_item(lua_State *L)
     294             : {
     295           0 :         NO_MAP_LOCK_REQUIRED;
     296           0 :         InvRef *ref = checkobject(L, 1);
     297           0 :         const char *listname = luaL_checkstring(L, 2);
     298           0 :         ItemStack item = read_item(L, 3, getServer(L));
     299           0 :         InventoryList *list = getlist(L, ref, listname);
     300           0 :         if(list){
     301           0 :                 ItemStack leftover = list->addItem(item);
     302           0 :                 if(leftover.count != item.count)
     303           0 :                         reportInventoryChange(L, ref);
     304           0 :                 LuaItemStack::create(L, leftover);
     305             :         } else {
     306           0 :                 LuaItemStack::create(L, item);
     307             :         }
     308           0 :         return 1;
     309             : }
     310             : 
     311             : // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
     312             : // Returns true if the item completely fits into the list
     313           0 : int InvRef::l_room_for_item(lua_State *L)
     314             : {
     315           0 :         NO_MAP_LOCK_REQUIRED;
     316           0 :         InvRef *ref = checkobject(L, 1);
     317           0 :         const char *listname = luaL_checkstring(L, 2);
     318           0 :         ItemStack item = read_item(L, 3, getServer(L));
     319           0 :         InventoryList *list = getlist(L, ref, listname);
     320           0 :         if(list){
     321           0 :                 lua_pushboolean(L, list->roomForItem(item));
     322             :         } else {
     323           0 :                 lua_pushboolean(L, false);
     324             :         }
     325           0 :         return 1;
     326             : }
     327             : 
     328             : // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
     329             : // Returns true if the list contains the given count of the given item name
     330           0 : int InvRef::l_contains_item(lua_State *L)
     331             : {
     332           0 :         NO_MAP_LOCK_REQUIRED;
     333           0 :         InvRef *ref = checkobject(L, 1);
     334           0 :         const char *listname = luaL_checkstring(L, 2);
     335           0 :         ItemStack item = read_item(L, 3, getServer(L));
     336           0 :         InventoryList *list = getlist(L, ref, listname);
     337           0 :         if(list){
     338           0 :                 lua_pushboolean(L, list->containsItem(item));
     339             :         } else {
     340           0 :                 lua_pushboolean(L, false);
     341             :         }
     342           0 :         return 1;
     343             : }
     344             : 
     345             : // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
     346             : // Returns the items that were actually removed
     347           0 : int InvRef::l_remove_item(lua_State *L)
     348             : {
     349           0 :         NO_MAP_LOCK_REQUIRED;
     350           0 :         InvRef *ref = checkobject(L, 1);
     351           0 :         const char *listname = luaL_checkstring(L, 2);
     352           0 :         ItemStack item = read_item(L, 3, getServer(L));
     353           0 :         InventoryList *list = getlist(L, ref, listname);
     354           0 :         if(list){
     355           0 :                 ItemStack removed = list->removeItem(item);
     356           0 :                 if(!removed.empty())
     357           0 :                         reportInventoryChange(L, ref);
     358           0 :                 LuaItemStack::create(L, removed);
     359             :         } else {
     360           0 :                 LuaItemStack::create(L, ItemStack());
     361             :         }
     362           0 :         return 1;
     363             : }
     364             : 
     365             : // get_location() -> location (like get_inventory(location))
     366           0 : int InvRef::l_get_location(lua_State *L)
     367             : {
     368           0 :         NO_MAP_LOCK_REQUIRED;
     369           0 :         InvRef *ref = checkobject(L, 1);
     370           0 :         const InventoryLocation &loc = ref->m_loc;
     371           0 :         switch(loc.type){
     372             :         case InventoryLocation::PLAYER:
     373           0 :                 lua_newtable(L);
     374           0 :                 lua_pushstring(L, "player");
     375           0 :                 lua_setfield(L, -2, "type");
     376           0 :                 lua_pushstring(L, loc.name.c_str());
     377           0 :                 lua_setfield(L, -2, "name");
     378           0 :                 return 1;
     379             :         case InventoryLocation::NODEMETA:
     380           0 :                 lua_newtable(L);
     381           0 :                 lua_pushstring(L, "node");
     382           0 :                 lua_setfield(L, -2, "type");
     383           0 :                 push_v3s16(L, loc.p);
     384           0 :                 lua_setfield(L, -2, "pos");
     385           0 :                 return 1;
     386             :         case InventoryLocation::DETACHED:
     387           0 :                 lua_newtable(L);
     388           0 :                 lua_pushstring(L, "detached");
     389           0 :                 lua_setfield(L, -2, "type");
     390           0 :                 lua_pushstring(L, loc.name.c_str());
     391           0 :                 lua_setfield(L, -2, "name");
     392           0 :                 return 1;
     393             :         case InventoryLocation::UNDEFINED:
     394             :         case InventoryLocation::CURRENT_PLAYER:
     395           0 :                 break;
     396             :         }
     397           0 :         lua_newtable(L);
     398           0 :         lua_pushstring(L, "undefined");
     399           0 :         lua_setfield(L, -2, "type");
     400           0 :         return 1;
     401             : }
     402             : 
     403             : 
     404           0 : InvRef::InvRef(const InventoryLocation &loc):
     405           0 :         m_loc(loc)
     406             : {
     407           0 : }
     408             : 
     409           0 : InvRef::~InvRef()
     410             : {
     411           0 : }
     412             : 
     413             : // Creates an InvRef and leaves it on top of stack
     414             : // Not callable from Lua; all references are created on the C side.
     415           0 : void InvRef::create(lua_State *L, const InventoryLocation &loc)
     416             : {
     417           0 :         NO_MAP_LOCK_REQUIRED;
     418           0 :         InvRef *o = new InvRef(loc);
     419           0 :         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
     420           0 :         luaL_getmetatable(L, className);
     421           0 :         lua_setmetatable(L, -2);
     422           0 : }
     423           0 : void InvRef::createPlayer(lua_State *L, Player *player)
     424             : {
     425           0 :         NO_MAP_LOCK_REQUIRED;
     426           0 :         InventoryLocation loc;
     427           0 :         loc.setPlayer(player->getName());
     428           0 :         create(L, loc);
     429           0 : }
     430           0 : void InvRef::createNodeMeta(lua_State *L, v3s16 p)
     431             : {
     432           0 :         InventoryLocation loc;
     433           0 :         loc.setNodeMeta(p);
     434           0 :         create(L, loc);
     435           0 : }
     436             : 
     437           0 : void InvRef::Register(lua_State *L)
     438             : {
     439           0 :         lua_newtable(L);
     440           0 :         int methodtable = lua_gettop(L);
     441           0 :         luaL_newmetatable(L, className);
     442           0 :         int metatable = lua_gettop(L);
     443             : 
     444           0 :         lua_pushliteral(L, "__metatable");
     445           0 :         lua_pushvalue(L, methodtable);
     446           0 :         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
     447             : 
     448           0 :         lua_pushliteral(L, "__index");
     449           0 :         lua_pushvalue(L, methodtable);
     450           0 :         lua_settable(L, metatable);
     451             : 
     452           0 :         lua_pushliteral(L, "__gc");
     453           0 :         lua_pushcfunction(L, gc_object);
     454           0 :         lua_settable(L, metatable);
     455             : 
     456           0 :         lua_pop(L, 1);  // drop metatable
     457             : 
     458           0 :         luaL_openlib(L, 0, methods, 0);  // fill methodtable
     459           0 :         lua_pop(L, 1);  // drop methodtable
     460             : 
     461             :         // Cannot be created from Lua
     462             :         //lua_register(L, className, create_object);
     463           0 : }
     464             : 
     465             : const char InvRef::className[] = "InvRef";
     466             : const luaL_reg InvRef::methods[] = {
     467             :         luamethod(InvRef, is_empty),
     468             :         luamethod(InvRef, get_size),
     469             :         luamethod(InvRef, set_size),
     470             :         luamethod(InvRef, get_width),
     471             :         luamethod(InvRef, set_width),
     472             :         luamethod(InvRef, get_stack),
     473             :         luamethod(InvRef, set_stack),
     474             :         luamethod(InvRef, get_list),
     475             :         luamethod(InvRef, set_list),
     476             :         luamethod(InvRef, get_lists),
     477             :         luamethod(InvRef, set_lists),
     478             :         luamethod(InvRef, add_item),
     479             :         luamethod(InvRef, room_for_item),
     480             :         luamethod(InvRef, contains_item),
     481             :         luamethod(InvRef, remove_item),
     482             :         luamethod(InvRef, get_location),
     483             :         {0,0}
     484             : };
     485             : 
     486             : // get_inventory(location)
     487           0 : int ModApiInventory::l_get_inventory(lua_State *L)
     488             : {
     489           0 :         InventoryLocation loc;
     490             : 
     491           0 :         std::string type = checkstringfield(L, 1, "type");
     492             : 
     493           0 :         if(type == "node"){
     494           0 :                 lua_getfield(L, 1, "pos");
     495           0 :                 v3s16 pos = check_v3s16(L, -1);
     496           0 :                 loc.setNodeMeta(pos);
     497             : 
     498           0 :                 if(getServer(L)->getInventory(loc) != NULL)
     499           0 :                         InvRef::create(L, loc);
     500             :                 else
     501           0 :                         lua_pushnil(L);
     502           0 :                 return 1;
     503             :         } else {
     504           0 :                 NO_MAP_LOCK_REQUIRED;
     505           0 :                 if(type == "player"){
     506           0 :                         std::string name = checkstringfield(L, 1, "name");
     507           0 :                         loc.setPlayer(name);
     508           0 :                 } else if(type == "detached"){
     509           0 :                         std::string name = checkstringfield(L, 1, "name");
     510           0 :                         loc.setDetached(name);
     511             :                 }
     512             : 
     513           0 :                 if(getServer(L)->getInventory(loc) != NULL)
     514           0 :                         InvRef::create(L, loc);
     515             :                 else
     516           0 :                         lua_pushnil(L);
     517           0 :                 return 1;       
     518             :                 // END NO_MAP_LOCK_REQUIRED;
     519             :         }
     520             : }
     521             : 
     522             : // create_detached_inventory_raw(name)
     523           0 : int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
     524             : {
     525           0 :         NO_MAP_LOCK_REQUIRED;
     526           0 :         const char *name = luaL_checkstring(L, 1);
     527           0 :         if(getServer(L)->createDetachedInventory(name) != NULL){
     528           0 :                 InventoryLocation loc;
     529           0 :                 loc.setDetached(name);
     530           0 :                 InvRef::create(L, loc);
     531             :         }else{
     532           0 :                 lua_pushnil(L);
     533             :         }
     534           0 :         return 1;
     535             : }
     536             : 
     537           0 : void ModApiInventory::Initialize(lua_State *L, int top)
     538             : {
     539           0 :         API_FCT(create_detached_inventory_raw);
     540           0 :         API_FCT(get_inventory);
     541           3 : }

Generated by: LCOV version 1.11