]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/script/lua_api/l_inventory.cpp
Script API: Check that SAOs are still usable before attempting to use them
[dragonfireclient.git] / src / script / lua_api / l_inventory.cpp
index 1404c3c8a026fcbf00ca6c57506f1cda50aeab8b..6e7afa4a4e67bf67575341f79af1ee72b1397d6e 100644 (file)
@@ -17,15 +17,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "cpp_api/scriptapi.h"
-#include "common/c_converter.h"
-#include "common/c_content.h"
 #include "lua_api/l_inventory.h"
+#include "lua_api/l_internal.h"
 #include "lua_api/l_item.h"
-#include "common/c_internal.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
 #include "server.h"
-#include "log.h"
-#include "inventorymanager.h"
+#include "remoteplayer.h"
 
 /*
        InvRef
@@ -40,7 +38,7 @@ InvRef* InvRef::checkobject(lua_State *L, int narg)
 
 Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
 {
-       return STACK_TO_SERVER(L)->getInventory(ref->m_loc);
+       return getServer(L)->getInventory(ref->m_loc);
 }
 
 InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
@@ -56,7 +54,7 @@ InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
 void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
 {
        // Inform other things that the inventory has changed
-       STACK_TO_SERVER(L)->setInventoryModified(ref->m_loc);
+       getServer(L)->setInventoryModified(ref->m_loc);
 }
 
 // Exported functions
@@ -119,21 +117,38 @@ int InvRef::l_set_size(lua_State *L)
        NO_MAP_LOCK_REQUIRED;
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
+
        int newsize = luaL_checknumber(L, 3);
+       if (newsize < 0) {
+               lua_pushboolean(L, false);
+               return 1;
+       }
+
        Inventory *inv = getinv(L, ref);
+       if(inv == NULL){
+               lua_pushboolean(L, false);
+               return 1;
+       }
        if(newsize == 0){
                inv->deleteList(listname);
                reportInventoryChange(L, ref);
-               return 0;
+               lua_pushboolean(L, true);
+               return 1;
        }
        InventoryList *list = inv->getList(listname);
        if(list){
                list->setSize(newsize);
        } else {
                list = inv->addList(listname, newsize);
+               if (!list)
+               {
+                       lua_pushboolean(L, false);
+                       return 1;
+               }
        }
        reportInventoryChange(L, ref);
-       return 0;
+       lua_pushboolean(L, true);
+       return 1;
 }
 
 // set_width(self, listname, size)
@@ -144,6 +159,9 @@ int InvRef::l_set_width(lua_State *L)
        const char *listname = luaL_checkstring(L, 2);
        int newwidth = luaL_checknumber(L, 3);
        Inventory *inv = getinv(L, ref);
+       if(inv == NULL){
+               return 0;
+       }
        InventoryList *list = inv->getList(listname);
        if(list){
                list->setWidth(newwidth);
@@ -176,7 +194,7 @@ int InvRef::l_set_stack(lua_State *L)
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
        int i = luaL_checknumber(L, 3) - 1;
-       ItemStack newitem = read_item(L, 4,STACK_TO_SERVER(L));
+       ItemStack newitem = read_item(L, 4, getServer(L)->idef());
        InventoryList *list = getlist(L, ref, listname);
        if(list != NULL && i >= 0 && i < (int) list->getSize()){
                list->changeItem(i, newitem);
@@ -195,7 +213,11 @@ int InvRef::l_get_list(lua_State *L)
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
        Inventory *inv = getinv(L, ref);
-       push_inventory_list(inv, listname, L);
+       if(inv){
+               push_inventory_list(L, inv, listname);
+       } else {
+               lua_pushnil(L);
+       }
        return 1;
 }
 
@@ -206,16 +228,66 @@ int InvRef::l_set_list(lua_State *L)
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
        Inventory *inv = getinv(L, ref);
+       if(inv == NULL){
+               return 0;
+       }
        InventoryList *list = inv->getList(listname);
        if(list)
-               read_inventory_list(inv, listname, L, 3,
-                               STACK_TO_SERVER(L),list->getSize());
+               read_inventory_list(L, 3, inv, listname,
+                               getServer(L), list->getSize());
        else
-               read_inventory_list(inv, listname, L, 3,STACK_TO_SERVER(L));
+               read_inventory_list(L, 3, inv, listname, getServer(L));
        reportInventoryChange(L, ref);
        return 0;
 }
 
+// get_lists(self) -> list of InventoryLists
+int InvRef::l_get_lists(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+       InvRef *ref = checkobject(L, 1);
+       Inventory *inv = getinv(L, ref);
+       if (!inv) {
+               return 0;
+       }
+       std::vector<const InventoryList*> lists = inv->getLists();
+       std::vector<const InventoryList*>::iterator iter = lists.begin();
+       lua_createtable(L, 0, lists.size());
+       for (; iter != lists.end(); iter++) {
+               const char* name = (*iter)->getName().c_str();
+               lua_pushstring(L, name);
+               push_inventory_list(L, inv, name);
+               lua_rawset(L, -3);
+       }
+       return 1;
+}
+
+// set_lists(self, lists)
+int InvRef::l_set_lists(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+       InvRef *ref = checkobject(L, 1);
+       Inventory *inv = getinv(L, ref);
+       if (!inv) {
+               return 0;
+       }
+
+       // Make a temporary inventory in case reading fails
+       Inventory *tempInv(inv);
+       tempInv->clear();
+
+       Server *server = getServer(L);
+
+       lua_pushnil(L);
+       while (lua_next(L, 2)) {
+               const char *listname = lua_tostring(L, -2);
+               read_inventory_list(L, -1, tempInv, listname, server);
+               lua_pop(L, 1);
+       }
+       inv = tempInv;
+       return 0;
+}
+
 // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
 // Returns the leftover stack
 int InvRef::l_add_item(lua_State *L)
@@ -223,7 +295,7 @@ int InvRef::l_add_item(lua_State *L)
        NO_MAP_LOCK_REQUIRED;
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
-       ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
+       ItemStack item = read_item(L, 3, getServer(L)->idef());
        InventoryList *list = getlist(L, ref, listname);
        if(list){
                ItemStack leftover = list->addItem(item);
@@ -243,7 +315,7 @@ int InvRef::l_room_for_item(lua_State *L)
        NO_MAP_LOCK_REQUIRED;
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
-       ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
+       ItemStack item = read_item(L, 3, getServer(L)->idef());
        InventoryList *list = getlist(L, ref, listname);
        if(list){
                lua_pushboolean(L, list->roomForItem(item));
@@ -253,17 +325,20 @@ int InvRef::l_room_for_item(lua_State *L)
        return 1;
 }
 
-// contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
-// Returns true if the list contains the given count of the given item name
+// contains_item(self, listname, itemstack or itemstring or table or nil, [match_meta]) -> true/false
+// Returns true if the list contains the given count of the given item
 int InvRef::l_contains_item(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
-       ItemStack item = read_item(L, 3, STACK_TO_SERVER(L));
+       ItemStack item = read_item(L, 3, getServer(L)->idef());
        InventoryList *list = getlist(L, ref, listname);
-       if(list){
-               lua_pushboolean(L, list->containsItem(item));
+       bool match_meta = false;
+       if (lua_isboolean(L, 4))
+               match_meta = readParam<bool>(L, 4);
+       if (list) {
+               lua_pushboolean(L, list->containsItem(item, match_meta));
        } else {
                lua_pushboolean(L, false);
        }
@@ -277,7 +352,7 @@ int InvRef::l_remove_item(lua_State *L)
        NO_MAP_LOCK_REQUIRED;
        InvRef *ref = checkobject(L, 1);
        const char *listname = luaL_checkstring(L, 2);
-       ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
+       ItemStack item = read_item(L, 3, getServer(L)->idef());
        InventoryList *list = getlist(L, ref, listname);
        if(list){
                ItemStack removed = list->removeItem(item);
@@ -290,7 +365,7 @@ int InvRef::l_remove_item(lua_State *L)
        return 1;
 }
 
-// get_location() -> location (like minetest.get_inventory(location))
+// get_location() -> location (like get_inventory(location))
 int InvRef::l_get_location(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
@@ -334,10 +409,6 @@ InvRef::InvRef(const InventoryLocation &loc):
 {
 }
 
-InvRef::~InvRef()
-{
-}
-
 // Creates an InvRef and leaves it on top of stack
 // Not callable from Lua; all references are created on the C side.
 void InvRef::create(lua_State *L, const InventoryLocation &loc)
@@ -348,7 +419,7 @@ void InvRef::create(lua_State *L, const InventoryLocation &loc)
        luaL_getmetatable(L, className);
        lua_setmetatable(L, -2);
 }
-void InvRef::createPlayer(lua_State *L, Player *player)
+void InvRef::createPlayer(lua_State *L, RemotePlayer *player)
 {
        NO_MAP_LOCK_REQUIRED;
        InventoryLocation loc;
@@ -391,7 +462,7 @@ void InvRef::Register(lua_State *L)
 }
 
 const char InvRef::className[] = "InvRef";
-const luaL_reg InvRef::methods[] = {
+const luaL_Reg InvRef::methods[] = {
        luamethod(InvRef, is_empty),
        luamethod(InvRef, get_size),
        luamethod(InvRef, set_size),
@@ -401,6 +472,8 @@ const luaL_reg InvRef::methods[] = {
        luamethod(InvRef, set_stack),
        luamethod(InvRef, get_list),
        luamethod(InvRef, set_list),
+       luamethod(InvRef, get_lists),
+       luamethod(InvRef, set_lists),
        luamethod(InvRef, add_item),
        luamethod(InvRef, room_for_item),
        luamethod(InvRef, contains_item),
@@ -417,63 +490,64 @@ int ModApiInventory::l_get_inventory(lua_State *L)
        std::string type = checkstringfield(L, 1, "type");
 
        if(type == "node"){
+               MAP_LOCK_REQUIRED;
                lua_getfield(L, 1, "pos");
                v3s16 pos = check_v3s16(L, -1);
                loc.setNodeMeta(pos);
 
-               if(getServer(L)->getInventory(loc) != NULL)
+               if (getServer(L)->getInventory(loc) != NULL)
                        InvRef::create(L, loc);
                else
                        lua_pushnil(L);
                return 1;
-       } else {
-               NO_MAP_LOCK_REQUIRED;
-               if(type == "player"){
-                       std::string name = checkstringfield(L, 1, "name");
-                       loc.setPlayer(name);
-               } else if(type == "detached"){
-                       std::string name = checkstringfield(L, 1, "name");
-                       loc.setDetached(name);
-               }
+       }
 
-               if(getServer(L)->getInventory(loc) != NULL)
-                       InvRef::create(L, loc);
-               else
-                       lua_pushnil(L);
-               return 1;       
-               // END NO_MAP_LOCK_REQUIRED;
+       NO_MAP_LOCK_REQUIRED;
+       if (type == "player") {
+               std::string name = checkstringfield(L, 1, "name");
+               loc.setPlayer(name);
+       } else if (type == "detached") {
+               std::string name = checkstringfield(L, 1, "name");
+               loc.setDetached(name);
        }
+
+       if (getServer(L)->getInventory(loc) != NULL)
+               InvRef::create(L, loc);
+       else
+               lua_pushnil(L);
+       return 1;
+       // END NO_MAP_LOCK_REQUIRED;
+
 }
 
-// create_detached_inventory_raw(name)
+// create_detached_inventory_raw(name, [player_name])
 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
        const char *name = luaL_checkstring(L, 1);
-       if(getServer(L)->createDetachedInventory(name) != NULL){
+       std::string player = readParam<std::string>(L, 2, "");
+       if (getServer(L)->createDetachedInventory(name, player) != NULL) {
                InventoryLocation loc;
                loc.setDetached(name);
                InvRef::create(L, loc);
-       }else{
+       } else {
                lua_pushnil(L);
        }
        return 1;
 }
 
-bool ModApiInventory::Initialize(lua_State *L, int top) {
-       bool retval = true;
-
-       retval &= API_FCT(create_detached_inventory_raw);
-       retval &= API_FCT(get_inventory);
-
-       InvRef::Register(L);
-
-       return retval;
+// remove_detached_inventory_raw(name)
+int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+       const std::string &name = luaL_checkstring(L, 1);
+       lua_pushboolean(L, getServer(L)->removeDetachedInventory(name));
+       return 1;
 }
 
-ModApiInventory::ModApiInventory()
-       : ModApiBase() {
-
+void ModApiInventory::Initialize(lua_State *L, int top)
+{
+       API_FCT(create_detached_inventory_raw);
+       API_FCT(remove_detached_inventory_raw);
+       API_FCT(get_inventory);
 }
-
-ModApiInventory modapiinventory_prototype;