]> git.lizzy.rs Git - minetest.git/blobdiff - src/inventorymanager.cpp
Make Lua error output in log clearer
[minetest.git] / src / inventorymanager.cpp
index 0149fd9abe758c154bf799659b384bd0d71104be..b04a1c1777522aec1af58e6399d78c796d4dcb23 100644 (file)
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "main.h"  // for g_settings
 #include "settings.h"
 #include "utility.h"
+#include "craftdef.h"
 
 /*
        InventoryLocation
@@ -124,10 +125,18 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
        {
                a = new IDropAction(is);
        }
+       else if(type == "Craft")
+       {
+               a = new ICraftAction(is);
+       }
 
        return a;
 }
 
+/*
+       IMoveAction
+*/
+
 IMoveAction::IMoveAction(std::istream &is)
 {
        std::string ts;
@@ -152,7 +161,7 @@ IMoveAction::IMoveAction(std::istream &is)
        to_i = stoi(ts);
 }
 
-void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player)
+void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
 {
        Inventory *inv_from = mgr->getInventory(from_inv);
        Inventory *inv_to = mgr->getInventory(to_inv);
@@ -188,59 +197,13 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player)
                                <<", to_list=\""<<to_list<<"\""<<std::endl;
                return;
        }
-       if(list_from->getItem(from_i).empty())
-       {
-               infostream<<"IMoveAction::apply(): FAIL: source item not found: "
-                               <<"from_inv=\""<<from_inv.dump()<<"\""
-                               <<", from_list=\""<<from_list<<"\""
-                               <<" from_i="<<from_i<<std::endl;
-               return;
-       }
        /*
-               If the source and the destination slots are the same
-       */
-       if(inv_from == inv_to && list_from == list_to && from_i == to_i)
-       {
-               infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
-                               <<"are the same: inv=\""<<from_inv.dump()
-                               <<"\" list=\""<<from_list
-                               <<"\" i="<<from_i<<std::endl;
-               return;
-       }
-       
-       // Take item from source list
-       ItemStack item1;
-       if(count == 0)
-               item1 = list_from->changeItem(from_i, ItemStack());
-       else
-               item1 = list_from->takeItem(from_i, count);
-
-       // Try to add the item to destination list
-       int oldcount = item1.count;
-       item1 = list_to->addItem(to_i, item1);
+               This performs the actual movement
 
-       // If something is returned, the item was not fully added
-       if(!item1.empty())
-       {
-               // If olditem is returned, nothing was added.
-               bool nothing_added = (item1.count == oldcount);
-               
-               // If something else is returned, part of the item was left unadded.
-               // Add the other part back to the source item
-               list_from->addItem(from_i, item1);
-
-               // If olditem is returned, nothing was added.
-               // Swap the items
-               if(nothing_added)
-               {
-                       // Take item from source list
-                       item1 = list_from->changeItem(from_i, ItemStack());
-                       // Adding was not possible, swap the items.
-                       ItemStack item2 = list_to->changeItem(to_i, item1);
-                       // Put item from destination list to the source list
-                       list_from->changeItem(from_i, item2);
-               }
-       }
+               If something is wrong (source item is empty, destination is the
+               same as source), nothing happens
+       */
+       list_from->moveItem(from_i, list_to, to_i, count);
 
        mgr->setInventoryModified(from_inv);
        if(inv_from != inv_to)
@@ -257,6 +220,38 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player)
                        <<std::endl;
 }
 
+void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+       // Optional InventoryAction operation that is run on the client
+       // to make lag less apparent.
+
+       Inventory *inv_from = mgr->getInventory(from_inv);
+       Inventory *inv_to = mgr->getInventory(to_inv);
+       if(!inv_from || !inv_to)
+               return;
+
+       InventoryLocation current_player;
+       current_player.setCurrentPlayer();
+       Inventory *inv_player = mgr->getInventory(current_player);
+       if(inv_from != inv_player || inv_to != inv_player)
+               return;
+
+       InventoryList *list_from = inv_from->getList(from_list);
+       InventoryList *list_to = inv_to->getList(to_list);
+       if(!list_from || !list_to)
+               return;
+
+       list_from->moveItem(from_i, list_to, to_i, count);
+
+       mgr->setInventoryModified(from_inv);
+       if(inv_from != inv_to)
+               mgr->setInventoryModified(to_inv);
+}
+
+/*
+       IDropAction
+*/
+
 IDropAction::IDropAction(std::istream &is)
 {
        std::string ts;
@@ -273,7 +268,7 @@ IDropAction::IDropAction(std::istream &is)
        from_i = stoi(ts);
 }
 
-void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
+void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
 {
        Inventory *inv_from = mgr->getInventory(from_inv);
        
@@ -302,18 +297,28 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
                return;
        }
 
-       /*
-               Drop the item
-       */
-       ItemStack item = list_from->getItem(from_i);
-       if(scriptapi_item_on_drop(player->getEnv()->getLua(), item, player,
+       // Take item from source list
+       ItemStack item1;
+       if(count == 0)
+               item1 = list_from->changeItem(from_i, ItemStack());
+       else
+               item1 = list_from->takeItem(from_i, count);
+
+       // Drop the item and apply the returned ItemStack
+       ItemStack item2 = item1;
+       if(scriptapi_item_on_drop(player->getEnv()->getLua(), item2, player,
                                player->getBasePosition() + v3f(0,1,0)))
        {
-               // Apply returned ItemStack
-               if(g_settings->getBool("creative_mode") == false
-                               || from_inv.type != InventoryLocation::PLAYER)
-                       list_from->changeItem(from_i, item);
-               mgr->setInventoryModified(from_inv);
+               if(g_settings->getBool("creative_mode") == true
+                               && from_inv.type == InventoryLocation::PLAYER)
+                       item2 = item1;  // creative mode
+
+               list_from->addItem(from_i, item2);
+
+               // Unless we have put the same amount back as we took in the first place,
+               // set inventory modified flag
+               if(item2.count != item1.count)
+                       mgr->setInventoryModified(from_inv);
        }
 
        infostream<<"IDropAction::apply(): dropped "
@@ -322,3 +327,157 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
                        <<" i="<<from_i
                        <<std::endl;
 }
+
+void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+       // Optional InventoryAction operation that is run on the client
+       // to make lag less apparent.
+
+       Inventory *inv_from = mgr->getInventory(from_inv);
+       if(!inv_from)
+               return;
+
+       InventoryLocation current_player;
+       current_player.setCurrentPlayer();
+       Inventory *inv_player = mgr->getInventory(current_player);
+       if(inv_from != inv_player)
+               return;
+
+       InventoryList *list_from = inv_from->getList(from_list);
+       if(!list_from)
+               return;
+
+       if(count == 0)
+               list_from->changeItem(from_i, ItemStack());
+       else
+               list_from->takeItem(from_i, count);
+
+       mgr->setInventoryModified(from_inv);
+}
+
+/*
+       ICraftAction
+*/
+
+ICraftAction::ICraftAction(std::istream &is)
+{
+       std::string ts;
+
+       std::getline(is, ts, ' ');
+       count = stoi(ts);
+
+       std::getline(is, ts, ' ');
+       craft_inv.deSerialize(ts);
+}
+
+void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
+{
+       Inventory *inv_craft = mgr->getInventory(craft_inv);
+       
+       if(!inv_craft){
+               infostream<<"ICraftAction::apply(): FAIL: inventory not found: "
+                               <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+               return;
+       }
+
+       InventoryList *list_craft = inv_craft->getList("craft");
+       InventoryList *list_craftresult = inv_craft->getList("craftresult");
+
+       /*
+               If a list doesn't exist or the source item doesn't exist
+       */
+       if(!list_craft){
+               infostream<<"ICraftAction::apply(): FAIL: craft list not found: "
+                               <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+               return;
+       }
+       if(!list_craftresult){
+               infostream<<"ICraftAction::apply(): FAIL: craftresult list not found: "
+                               <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+               return;
+       }
+       if(list_craftresult->getSize() < 1){
+               infostream<<"ICraftAction::apply(): FAIL: craftresult list too short: "
+                               <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+               return;
+       }
+
+       ItemStack crafted;
+       int count_remaining = count;
+       bool found = getCraftingResult(inv_craft, crafted, false, gamedef);
+
+       while(found && list_craftresult->itemFits(0, crafted))
+       {
+               // Decrement input and add crafting output
+               getCraftingResult(inv_craft, crafted, true, gamedef);
+               list_craftresult->addItem(0, crafted);
+               mgr->setInventoryModified(craft_inv);
+
+               actionstream<<player->getDescription()
+                               <<" crafts "
+                               <<crafted.getItemString()
+                               <<std::endl;
+
+               // Decrement counter
+               if(count_remaining == 1)
+                       break;
+               else if(count_remaining > 1)
+                       count_remaining--;
+
+               // Get next crafting result
+               found = getCraftingResult(inv_craft, crafted, false, gamedef);
+       }
+
+       infostream<<"ICraftAction::apply(): crafted "
+                       <<" craft_inv=\""<<craft_inv.dump()<<"\""
+                       <<std::endl;
+}
+
+void ICraftAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+       // Optional InventoryAction operation that is run on the client
+       // to make lag less apparent.
+}
+
+
+// Crafting helper
+bool getCraftingResult(Inventory *inv, ItemStack& result,
+               bool decrementInput, IGameDef *gamedef)
+{
+       DSTACK(__FUNCTION_NAME);
+       
+       result.clear();
+
+       // TODO: Allow different sizes of crafting grids
+
+       // Get the InventoryList in which we will operate
+       InventoryList *clist = inv->getList("craft");
+       if(!clist || clist->getSize() != 9)
+               return false;
+
+       // Mangle crafting grid to an another format
+       CraftInput ci;
+       ci.method = CRAFT_METHOD_NORMAL;
+       ci.width = 3;
+       for(u16 i=0; i<9; i++)
+               ci.items.push_back(clist->getItem(i));
+
+       // Find out what is crafted and add it to result item slot
+       CraftOutput co;
+       bool found = gamedef->getCraftDefManager()->getCraftResult(
+                       ci, co, decrementInput, gamedef);
+       if(found)
+               result.deSerialize(co.item, gamedef->getItemDefManager());
+
+       if(found && decrementInput)
+       {
+               // CraftInput has been changed, apply changes in clist
+               for(u16 i=0; i<9; i++)
+               {
+                       clist->changeItem(i, ci.items[i]);
+               }
+       }
+
+       return found;
+}
+