rollback_interface.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "rollback_interface.h"
  17. #include <sstream>
  18. #include "util/serialize.h"
  19. #include "util/string.h"
  20. #include "util/numeric.h"
  21. #include "map.h"
  22. #include "gamedef.h"
  23. #include "nodedef.h"
  24. #include "nodemetadata.h"
  25. #include "exceptions.h"
  26. #include "log.h"
  27. #include "inventorymanager.h"
  28. #include "inventory.h"
  29. #include "irrlicht_changes/printing.h"
  30. #include "mapblock.h"
  31. RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef)
  32. {
  33. const NodeDefManager *ndef = gamedef->ndef();
  34. MapNode n = map->getNode(p);
  35. name = ndef->get(n).name;
  36. param1 = n.param1;
  37. param2 = n.param2;
  38. NodeMetadata *metap = map->getNodeMetadata(p);
  39. if (metap) {
  40. std::ostringstream os(std::ios::binary);
  41. metap->serialize(os, 1); // FIXME: version bump??
  42. meta = os.str();
  43. }
  44. }
  45. std::string RollbackAction::toString() const
  46. {
  47. std::ostringstream os(std::ios::binary);
  48. switch (type) {
  49. case TYPE_SET_NODE:
  50. os << "set_node " << p;
  51. os << ": (" << serializeJsonString(n_old.name);
  52. os << ", " << itos(n_old.param1);
  53. os << ", " << itos(n_old.param2);
  54. os << ", " << serializeJsonString(n_old.meta);
  55. os << ") -> (" << serializeJsonString(n_new.name);
  56. os << ", " << itos(n_new.param1);
  57. os << ", " << itos(n_new.param2);
  58. os << ", " << serializeJsonString(n_new.meta);
  59. os << ')';
  60. break;
  61. case TYPE_MODIFY_INVENTORY_STACK:
  62. os << "modify_inventory_stack (";
  63. os << serializeJsonString(inventory_location);
  64. os << ", " << serializeJsonString(inventory_list);
  65. os << ", " << inventory_index;
  66. os << ", " << (inventory_add ? "add" : "remove");
  67. os << ", " << serializeJsonString(inventory_stack.getItemString());
  68. os << ')';
  69. break;
  70. default:
  71. return "<unknown action>";
  72. }
  73. return os.str();
  74. }
  75. bool RollbackAction::isImportant(IGameDef *gamedef) const
  76. {
  77. if (type != TYPE_SET_NODE)
  78. return true;
  79. // If names differ, action is always important
  80. if(n_old.name != n_new.name)
  81. return true;
  82. // If metadata differs, action is always important
  83. if(n_old.meta != n_new.meta)
  84. return true;
  85. const NodeDefManager *ndef = gamedef->ndef();
  86. // Both are of the same name, so a single definition is needed
  87. const ContentFeatures &def = ndef->get(n_old.name);
  88. // If the type is flowing liquid, action is not important
  89. if (def.liquid_type == LIQUID_FLOWING)
  90. return false;
  91. // Otherwise action is important
  92. return true;
  93. }
  94. bool RollbackAction::getPosition(v3s16 *dst) const
  95. {
  96. switch (type) {
  97. case TYPE_SET_NODE:
  98. if (dst) *dst = p;
  99. return true;
  100. case TYPE_MODIFY_INVENTORY_STACK: {
  101. InventoryLocation loc;
  102. loc.deSerialize(inventory_location);
  103. if (loc.type != InventoryLocation::NODEMETA) {
  104. return false;
  105. }
  106. if (dst) *dst = loc.p;
  107. return true; }
  108. default:
  109. return false;
  110. }
  111. }
  112. bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gamedef) const
  113. {
  114. try {
  115. switch (type) {
  116. case TYPE_NOTHING:
  117. return true;
  118. case TYPE_SET_NODE: {
  119. const NodeDefManager *ndef = gamedef->ndef();
  120. // Make sure position is loaded from disk
  121. map->emergeBlock(getContainerPos(p, MAP_BLOCKSIZE), false);
  122. // Check current node
  123. MapNode current_node = map->getNode(p);
  124. std::string current_name = ndef->get(current_node).name;
  125. // If current node not the new node, it's bad
  126. if (current_name != n_new.name) {
  127. return false;
  128. }
  129. // Create rollback node
  130. content_t id = CONTENT_IGNORE;
  131. if (!ndef->getId(n_old.name, id)) {
  132. // The old node is not registered
  133. return false;
  134. }
  135. MapNode n(id, n_old.param1, n_old.param2);
  136. // Set rollback node
  137. try {
  138. if (!map->addNodeWithEvent(p, n)) {
  139. infostream << "RollbackAction::applyRevert(): "
  140. << "AddNodeWithEvent failed at "
  141. << p << " for " << n_old.name
  142. << std::endl;
  143. return false;
  144. }
  145. if (n_old.meta.empty()) {
  146. map->removeNodeMetadata(p);
  147. } else {
  148. NodeMetadata *meta = map->getNodeMetadata(p);
  149. if (!meta) {
  150. meta = new NodeMetadata(gamedef->idef());
  151. if (!map->setNodeMetadata(p, meta)) {
  152. delete meta;
  153. infostream << "RollbackAction::applyRevert(): "
  154. << "setNodeMetadata failed at "
  155. << p << " for " << n_old.name
  156. << std::endl;
  157. return false;
  158. }
  159. }
  160. std::istringstream is(n_old.meta, std::ios::binary);
  161. meta->deSerialize(is, 1); // FIXME: version bump??
  162. }
  163. // Inform other things that the meta data has changed
  164. MapEditEvent event;
  165. event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
  166. event.setPositionModified(p);
  167. map->dispatchEvent(event);
  168. } catch (InvalidPositionException &e) {
  169. infostream << "RollbackAction::applyRevert(): "
  170. << "InvalidPositionException: " << e.what()
  171. << std::endl;
  172. return false;
  173. }
  174. // Success
  175. return true; }
  176. case TYPE_MODIFY_INVENTORY_STACK: {
  177. InventoryLocation loc;
  178. loc.deSerialize(inventory_location);
  179. Inventory *inv = imgr->getInventory(loc);
  180. if (!inv) {
  181. infostream << "RollbackAction::applyRevert(): Could not get "
  182. "inventory at " << inventory_location << std::endl;
  183. return false;
  184. }
  185. InventoryList *list = inv->getList(inventory_list);
  186. if (!list) {
  187. infostream << "RollbackAction::applyRevert(): Could not get "
  188. "inventory list \"" << inventory_list << "\" in "
  189. << inventory_location << std::endl;
  190. return false;
  191. }
  192. if (list->getSize() <= inventory_index) {
  193. infostream << "RollbackAction::applyRevert(): List index "
  194. << inventory_index << " too large in "
  195. << "inventory list \"" << inventory_list << "\" in "
  196. << inventory_location << std::endl;
  197. return false;
  198. }
  199. // If item was added, take away item, otherwise add removed item
  200. if (inventory_add) {
  201. // Silently ignore different current item
  202. if (list->getItem(inventory_index).name !=
  203. gamedef->idef()->getAlias(inventory_stack.name))
  204. return false;
  205. list->takeItem(inventory_index, inventory_stack.count);
  206. } else {
  207. list->addItem(inventory_index, inventory_stack);
  208. }
  209. // Inventory was modified; send to clients
  210. imgr->setInventoryModified(loc);
  211. return true; }
  212. default:
  213. errorstream << "RollbackAction::applyRevert(): type not handled"
  214. << std::endl;
  215. return false;
  216. }
  217. } catch(SerializationError &e) {
  218. errorstream << "RollbackAction::applyRevert(): n_old.name=" << n_old.name
  219. << ", SerializationError: " << e.what() << std::endl;
  220. }
  221. return false;
  222. }