LCOV - code coverage report
Current view: top level - src - rollback_interface.cpp (source / functions) Hit Total Coverage
Test: report Lines: 13 132 9.8 %
Date: 2015-07-11 18:23:49 Functions: 3 7 42.9 %

          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 "rollback_interface.h"
      21             : #include <sstream>
      22             : #include "util/serialize.h"
      23             : #include "util/string.h"
      24             : #include "util/numeric.h"
      25             : #include "map.h"
      26             : #include "gamedef.h"
      27             : #include "nodedef.h"
      28             : #include "nodemetadata.h"
      29             : #include "exceptions.h"
      30             : #include "log.h"
      31             : #include "inventorymanager.h"
      32             : #include "inventory.h"
      33             : #include "mapblock.h"
      34             : 
      35             : #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
      36             : 
      37             : 
      38          55 : RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef)
      39             : {
      40          55 :         INodeDefManager *ndef = gamedef->ndef();
      41          55 :         MapNode n = map->getNodeNoEx(p);
      42          55 :         name = ndef->get(n).name;
      43          55 :         param1 = n.param1;
      44          55 :         param2 = n.param2;
      45          55 :         NodeMetadata *metap = map->getNodeMetadata(p);
      46          55 :         if (metap) {
      47          46 :                 std::ostringstream os(std::ios::binary);
      48          23 :                 metap->serialize(os);
      49          23 :                 meta = os.str();
      50             :         }
      51          55 : }
      52             : 
      53             : 
      54           0 : std::string RollbackAction::toString() const
      55             : {
      56           0 :         std::ostringstream os(std::ios::binary);
      57           0 :         switch (type) {
      58             :         case TYPE_SET_NODE:
      59           0 :                 os << "set_node " << PP(p);
      60           0 :                 os << ": (" << serializeJsonString(n_old.name);
      61           0 :                 os << ", " << itos(n_old.param1);
      62           0 :                 os << ", " << itos(n_old.param2);
      63           0 :                 os << ", " << serializeJsonString(n_old.meta);
      64           0 :                 os << ") -> (" << serializeJsonString(n_new.name);
      65           0 :                 os << ", " << itos(n_new.param1);
      66           0 :                 os << ", " << itos(n_new.param2);
      67           0 :                 os << ", " << serializeJsonString(n_new.meta);
      68           0 :                 os << ')';
      69             :         case TYPE_MODIFY_INVENTORY_STACK:
      70           0 :                 os << "modify_inventory_stack (";
      71           0 :                 os << serializeJsonString(inventory_location);
      72           0 :                 os << ", " << serializeJsonString(inventory_list);
      73           0 :                 os << ", " << inventory_index;
      74           0 :                 os << ", " << (inventory_add ? "add" : "remove");
      75           0 :                 os << ", " << serializeJsonString(inventory_stack.getItemString());
      76           0 :                 os << ')';
      77             :         default:
      78           0 :                 return "<unknown action>";
      79             :         }
      80             :         return os.str();
      81             : }
      82             : 
      83             : 
      84           0 : bool RollbackAction::isImportant(IGameDef *gamedef) const
      85             : {
      86           0 :         if (type != TYPE_SET_NODE)
      87           0 :                 return true;
      88             :         // If names differ, action is always important
      89           0 :         if(n_old.name != n_new.name)
      90           0 :                 return true;
      91             :         // If metadata differs, action is always important
      92           0 :         if(n_old.meta != n_new.meta)
      93           0 :                 return true;
      94           0 :         INodeDefManager *ndef = gamedef->ndef();
      95             :         // Both are of the same name, so a single definition is needed
      96           0 :         const ContentFeatures &def = ndef->get(n_old.name);
      97             :         // If the type is flowing liquid, action is not important
      98           0 :         if (def.liquid_type == LIQUID_FLOWING)
      99           0 :                 return false;
     100             :         // Otherwise action is important
     101           0 :         return true;
     102             : }
     103             : 
     104             : 
     105           0 : bool RollbackAction::getPosition(v3s16 *dst) const
     106             : {
     107           0 :         switch (type) {
     108             :         case TYPE_SET_NODE:
     109           0 :                 if (dst) *dst = p;
     110           0 :                 return true;
     111             :         case TYPE_MODIFY_INVENTORY_STACK: {
     112           0 :                 InventoryLocation loc;
     113           0 :                 loc.deSerialize(inventory_location);
     114           0 :                 if (loc.type != InventoryLocation::NODEMETA) {
     115           0 :                         return false;
     116             :                 }
     117           0 :                 if (dst) *dst = loc.p;
     118           0 :                 return true; }
     119             :         default:
     120           0 :                 return false;
     121             :         }
     122             : }
     123             : 
     124             : 
     125           0 : bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gamedef) const
     126             : {
     127             :         try {
     128           0 :                 switch (type) {
     129             :                 case TYPE_NOTHING:
     130           0 :                         return true;
     131             :                 case TYPE_SET_NODE: {
     132           0 :                         INodeDefManager *ndef = gamedef->ndef();
     133             :                         // Make sure position is loaded from disk
     134           0 :                         map->emergeBlock(getContainerPos(p, MAP_BLOCKSIZE), false);
     135             :                         // Check current node
     136           0 :                         MapNode current_node = map->getNodeNoEx(p);
     137           0 :                         std::string current_name = ndef->get(current_node).name;
     138             :                         // If current node not the new node, it's bad
     139           0 :                         if (current_name != n_new.name) {
     140           0 :                                 return false;
     141             :                         }
     142             :                         // Create rollback node
     143           0 :                         MapNode n(ndef, n_old.name, n_old.param1, n_old.param2);
     144             :                         // Set rollback node
     145             :                         try {
     146           0 :                                 if (!map->addNodeWithEvent(p, n)) {
     147           0 :                                         infostream << "RollbackAction::applyRevert(): "
     148           0 :                                                 << "AddNodeWithEvent failed at "
     149           0 :                                                 << PP(p) << " for " << n_old.name
     150           0 :                                                 << std::endl;
     151           0 :                                         return false;
     152             :                                 }
     153           0 :                                 if (n_old.meta.empty()) {
     154           0 :                                         map->removeNodeMetadata(p);
     155             :                                 } else {
     156           0 :                                         NodeMetadata *meta = map->getNodeMetadata(p);
     157           0 :                                         if (!meta) {
     158           0 :                                                 meta = new NodeMetadata(gamedef);
     159           0 :                                                 if (!map->setNodeMetadata(p, meta)) {
     160           0 :                                                         delete meta;
     161           0 :                                                         infostream << "RollbackAction::applyRevert(): "
     162           0 :                                                                 << "setNodeMetadata failed at "
     163           0 :                                                                 << PP(p) << " for " << n_old.name
     164           0 :                                                                 << std::endl;
     165           0 :                                                         return false;
     166             :                                                 }
     167             :                                         }
     168           0 :                                         std::istringstream is(n_old.meta, std::ios::binary);
     169           0 :                                         meta->deSerialize(is);
     170             :                                 }
     171             :                                 // Inform other things that the meta data has changed
     172           0 :                                 v3s16 blockpos = getContainerPos(p, MAP_BLOCKSIZE);
     173           0 :                                 MapEditEvent event;
     174           0 :                                 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
     175           0 :                                 event.p = blockpos;
     176           0 :                                 map->dispatchEvent(&event);
     177             :                                 // Set the block to be saved
     178           0 :                                 MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
     179           0 :                                 if (block) {
     180             :                                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
     181           0 :                                                 MOD_REASON_REPORT_META_CHANGE);
     182             :                                 }
     183           0 :                         } catch (InvalidPositionException &e) {
     184           0 :                                 infostream << "RollbackAction::applyRevert(): "
     185           0 :                                         << "InvalidPositionException: " << e.what()
     186           0 :                                         << std::endl;
     187           0 :                                 return false;
     188             :                         }
     189             :                         // Success
     190           0 :                         return true; }
     191             :                 case TYPE_MODIFY_INVENTORY_STACK: {
     192           0 :                         InventoryLocation loc;
     193           0 :                         loc.deSerialize(inventory_location);
     194           0 :                         std::string real_name = gamedef->idef()->getAlias(inventory_stack.name);
     195           0 :                         Inventory *inv = imgr->getInventory(loc);
     196           0 :                         if (!inv) {
     197             :                                 infostream << "RollbackAction::applyRevert(): Could not get "
     198           0 :                                         "inventory at " << inventory_location << std::endl;
     199           0 :                                 return false;
     200             :                         }
     201           0 :                         InventoryList *list = inv->getList(inventory_list);
     202           0 :                         if (!list) {
     203             :                                 infostream << "RollbackAction::applyRevert(): Could not get "
     204           0 :                                         "inventory list \"" << inventory_list << "\" in "
     205           0 :                                         << inventory_location << std::endl;
     206           0 :                                 return false;
     207             :                         }
     208           0 :                         if (list->getSize() <= inventory_index) {
     209           0 :                                 infostream << "RollbackAction::applyRevert(): List index "
     210           0 :                                         << inventory_index << " too large in "
     211           0 :                                         << "inventory list \"" << inventory_list << "\" in "
     212           0 :                                         << inventory_location << std::endl;
     213             :                         }
     214             :                         // If item was added, take away item, otherwise add removed item
     215           0 :                         if (inventory_add) {
     216             :                                 // Silently ignore different current item
     217           0 :                                 if (list->getItem(inventory_index).name != real_name)
     218           0 :                                         return false;
     219           0 :                                 list->takeItem(inventory_index, inventory_stack.count);
     220             :                         } else {
     221           0 :                                 list->addItem(inventory_index, inventory_stack);
     222             :                         }
     223             :                         // Inventory was modified; send to clients
     224           0 :                         imgr->setInventoryModified(loc);
     225           0 :                         return true; }
     226             :                 default:
     227           0 :                         errorstream << "RollbackAction::applyRevert(): type not handled"
     228           0 :                                 << std::endl;
     229           0 :                         return false;
     230             :                 }
     231           0 :         } catch(SerializationError &e) {
     232           0 :                 errorstream << "RollbackAction::applyRevert(): n_old.name=" << n_old.name
     233           0 :                                 << ", SerializationError: " << e.what() << std::endl;
     234             :         }
     235           0 :         return false;
     236           3 : }
     237             : 

Generated by: LCOV version 1.11