/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "rollback_interface.h" #include #include "util/serialize.h" #include "util/string.h" #include "util/numeric.h" #include "map.h" #include "gamedef.h" #include "nodedef.h" #include "nodemetadata.h" #include "exceptions.h" #include "log.h" #include "inventorymanager.h" #include "inventory.h" #include "mapblock.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef) { INodeDefManager *ndef = gamedef->ndef(); MapNode n = map->getNodeNoEx(p); name = ndef->get(n).name; param1 = n.param1; param2 = n.param2; NodeMetadata *metap = map->getNodeMetadata(p); if(metap){ std::ostringstream os(std::ios::binary); metap->serialize(os); meta = os.str(); } } std::string RollbackAction::toString() const { switch(type){ case TYPE_SET_NODE: { std::ostringstream os(std::ios::binary); os<<"[set_node"; os<<" "; os<<"("<ndef(); // Both are of the same name, so a single definition is needed const ContentFeatures &def = ndef->get(n_old.name); // If the type is flowing liquid, action is not important if(def.liquid_type == LIQUID_FLOWING) return false; // Otherwise action is important return true; } default: return true; } } bool RollbackAction::getPosition(v3s16 *dst) const { switch(type){ case RollbackAction::TYPE_SET_NODE: if(dst) *dst = p; return true; case RollbackAction::TYPE_MODIFY_INVENTORY_STACK: { InventoryLocation loc; loc.deSerialize(inventory_location); if(loc.type != InventoryLocation::NODEMETA) return false; if(dst) *dst = loc.p; return true; } default: return false; } } bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gamedef) const { try{ switch(type){ case TYPE_NOTHING: return true; case TYPE_SET_NODE: { INodeDefManager *ndef = gamedef->ndef(); // Make sure position is loaded from disk map->emergeBlock(getContainerPos(p, MAP_BLOCKSIZE), false); // Check current node MapNode current_node = map->getNodeNoEx(p); std::string current_name = ndef->get(current_node).name; // If current node not the new node, it's bad if(current_name != n_new.name) return false; /*// If current node not the new node and not ignore, it's bad if(current_name != n_new.name && current_name != "ignore") return false;*/ // Create rollback node MapNode n(ndef, n_old.name, n_old.param1, n_old.param2); // Set rollback node try{ if(!map->addNodeWithEvent(p, n)){ infostream<<"RollbackAction::applyRevert(): " <<"AddNodeWithEvent failed at " <getNodeMetadata(p); if(n_old.meta != ""){ if(!meta){ meta = new NodeMetadata(gamedef); map->setNodeMetadata(p, meta); } std::istringstream is(n_old.meta, std::ios::binary); meta->deSerialize(is); } else { map->removeNodeMetadata(p); } // NOTE: This same code is in scriptapi.cpp // Inform other things that the metadata has changed v3s16 blockpos = getContainerPos(p, MAP_BLOCKSIZE); MapEditEvent event; event.type = MEET_BLOCK_NODE_METADATA_CHANGED; event.p = blockpos; map->dispatchEvent(&event); // Set the block to be saved MapBlock *block = map->getBlockNoCreateNoEx(blockpos); if(block) block->raiseModified(MOD_STATE_WRITE_NEEDED, "NodeMetaRef::reportMetadataChange"); }catch(InvalidPositionException &e){ infostream<<"RollbackAction::applyRevert(): " <<"InvalidPositionException: "<idef()); Inventory *inv = imgr->getInventory(loc); if(!inv){ infostream<<"RollbackAction::applyRevert(): Could not get " "inventory at "<getList(inventory_list); if(!list){ infostream<<"RollbackAction::applyRevert(): Could not get " "inventory list \""<getSize() <= inventory_index){ infostream<<"RollbackAction::applyRevert(): List index " <getItem(inventory_index).name != stack.name) return false; list->takeItem(inventory_index, stack.count); } else { list->addItem(inventory_index, stack); } // Inventory was modified; send to clients imgr->setInventoryModified(loc); return true; } default: errorstream<<"RollbackAction::applyRevert(): type not handled" <