From 0190f9b077dcb2b8cb41c622dd91ffc1e04dacac Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Thu, 26 Jul 2012 22:06:45 +0300 Subject: Experimental-ish rollback functionality --- src/rollback_interface.cpp | 398 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 src/rollback_interface.cpp (limited to 'src/rollback_interface.cpp') diff --git a/src/rollback_interface.cpp b/src/rollback_interface.cpp new file mode 100644 index 000000000..e15fe3da3 --- /dev/null +++ b/src/rollback_interface.cpp @@ -0,0 +1,398 @@ +/* +Minetest-c55 +Copyright (C) 2012 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::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" + <