Clean up rollback
[oweals/minetest.git] / src / rollback.cpp
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.h"
21 #include <fstream>
22 #include <list>
23 #include <sstream>
24 #include "log.h"
25 #include "mapnode.h"
26 #include "gamedef.h"
27 #include "nodedef.h"
28 #include "util/serialize.h"
29 #include "util/string.h"
30 #include "util/numeric.h"
31 #include "inventorymanager.h" // deserializing InventoryLocations
32 #include "sqlite3.h"
33 #include "filesys.h"
34
35 #define POINTS_PER_NODE (16.0)
36
37 #define SQLRES(f, good) \
38         if ((f) != (good)) {\
39                 throw FileNotGoodException(std::string("RollbackManager: " \
40                         "SQLite3 error (" __FILE__ ":" TOSTRING(__LINE__) \
41                         "): ") + sqlite3_errmsg(db)); \
42         }
43 #define SQLOK(f) SQLRES(f, SQLITE_OK)
44
45
46 class ItemStackRow : public ItemStack {
47 public:
48         ItemStackRow & operator = (const ItemStack & other)
49         {
50                 *static_cast<ItemStack *>(this) = other;
51                 return *this;
52         }
53
54         int id;
55 };
56
57 struct ActionRow {
58         int          id;
59         int          actor;
60         time_t       timestamp;
61         int          type;
62         std::string  location, list;
63         int          index, add;
64         ItemStackRow stack;
65         int          nodeMeta;
66         int          x, y, z;
67         int          oldNode;
68         int          oldParam1, oldParam2;
69         std::string  oldMeta;
70         int          newNode;
71         int          newParam1, newParam2;
72         std::string  newMeta;
73         int          guessed;
74 };
75
76
77 struct Entity {
78         int         id;
79         std::string name;
80 };
81
82
83
84 RollbackManager::RollbackManager(const std::string & world_path,
85                 IGameDef * gamedef_) :
86         gamedef(gamedef_),
87         current_actor_is_guess(false)
88 {
89         verbosestream << "RollbackManager::RollbackManager(" << world_path
90                 << ")" << std::endl;
91
92         std::string txt_filename = world_path + DIR_DELIM "rollback.txt";
93         std::string migrating_flag = txt_filename + ".migrating";
94         database_path = world_path + DIR_DELIM "rollback.sqlite";
95
96         initDatabase();
97
98         if (fs::PathExists(txt_filename) && (fs::PathExists(migrating_flag) ||
99                         !fs::PathExists(database_path))) {
100                 std::ofstream of(migrating_flag.c_str());
101                 of.close();
102                 migrate(txt_filename);
103                 fs::DeleteSingleFileOrEmptyDirectory(migrating_flag);
104         }
105 }
106
107
108 RollbackManager::~RollbackManager()
109 {
110         SQLOK(sqlite3_finalize(stmt_insert));
111         SQLOK(sqlite3_finalize(stmt_replace));
112         SQLOK(sqlite3_finalize(stmt_select));
113         SQLOK(sqlite3_finalize(stmt_select_range));
114         SQLOK(sqlite3_finalize(stmt_select_withActor));
115         SQLOK(sqlite3_finalize(stmt_knownActor_select));
116         SQLOK(sqlite3_finalize(stmt_knownActor_insert));
117         SQLOK(sqlite3_finalize(stmt_knownNode_select));
118         SQLOK(sqlite3_finalize(stmt_knownNode_insert));
119
120         SQLOK(sqlite3_close(db));
121 }
122
123
124 void RollbackManager::registerNewActor(const int id, const std::string &name)
125 {
126         Entity actor = {id, name};
127         knownActors.push_back(actor);
128 }
129
130
131 void RollbackManager::registerNewNode(const int id, const std::string &name)
132 {
133         Entity node = {id, name};
134         knownNodes.push_back(node);
135 }
136
137
138 int RollbackManager::getActorId(const std::string &name)
139 {
140         for (std::vector<Entity>::const_iterator iter = knownActors.begin();
141                         iter != knownActors.end(); ++iter) {
142                 if (iter->name == name) {
143                         return iter->id;
144                 }
145         }
146
147         SQLOK(sqlite3_bind_text(stmt_knownActor_insert, 1, name.c_str(), name.size(), NULL));
148         SQLRES(sqlite3_step(stmt_knownActor_insert), SQLITE_DONE);
149         SQLOK(sqlite3_reset(stmt_knownActor_insert));
150
151         int id = sqlite3_last_insert_rowid(db);
152         registerNewActor(id, name);
153
154         return id;
155 }
156
157
158 int RollbackManager::getNodeId(const std::string &name)
159 {
160         for (std::vector<Entity>::const_iterator iter = knownNodes.begin();
161                         iter != knownNodes.end(); ++iter) {
162                 if (iter->name == name) {
163                         return iter->id;
164                 }
165         }
166
167         SQLOK(sqlite3_bind_text(stmt_knownNode_insert, 1, name.c_str(), name.size(), NULL));
168         SQLRES(sqlite3_step(stmt_knownNode_insert), SQLITE_DONE);
169         SQLOK(sqlite3_reset(stmt_knownNode_insert));
170
171         int id = sqlite3_last_insert_rowid(db);
172         registerNewNode(id, name);
173
174         return id;
175 }
176
177
178 const char * RollbackManager::getActorName(const int id)
179 {
180         for (std::vector<Entity>::const_iterator iter = knownActors.begin();
181                         iter != knownActors.end(); ++iter) {
182                 if (iter->id == id) {
183                         return iter->name.c_str();
184                 }
185         }
186
187         return "";
188 }
189
190
191 const char * RollbackManager::getNodeName(const int id)
192 {
193         for (std::vector<Entity>::const_iterator iter = knownNodes.begin();
194                         iter != knownNodes.end(); ++iter) {
195                 if (iter->id == id) {
196                         return iter->name.c_str();
197                 }
198         }
199
200         return "";
201 }
202
203
204 bool RollbackManager::createTables()
205 {
206         SQLOK(sqlite3_exec(db,
207                 "CREATE TABLE IF NOT EXISTS `actor` (\n"
208                 "       `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
209                 "       `name` TEXT NOT NULL\n"
210                 ");\n"
211                 "CREATE TABLE IF NOT EXISTS `node` (\n"
212                 "       `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
213                 "       `name` TEXT NOT NULL\n"
214                 ");\n"
215                 "CREATE TABLE IF NOT EXISTS `action` (\n"
216                 "       `id` INTEGER PRIMARY KEY AUTOINCREMENT,\n"
217                 "       `actor` INTEGER NOT NULL,\n"
218                 "       `timestamp` TIMESTAMP NOT NULL,\n"
219                 "       `type` INTEGER NOT NULL,\n"
220                 "       `list` TEXT,\n"
221                 "       `index` INTEGER,\n"
222                 "       `add` INTEGER,\n"
223                 "       `stackNode` INTEGER,\n"
224                 "       `stackQuantity` INTEGER,\n"
225                 "       `nodeMeta` INTEGER,\n"
226                 "       `x` INT,\n"
227                 "       `y` INT,\n"
228                 "       `z` INT,\n"
229                 "       `oldNode` INTEGER,\n"
230                 "       `oldParam1` INTEGER,\n"
231                 "       `oldParam2` INTEGER,\n"
232                 "       `oldMeta` TEXT,\n"
233                 "       `newNode` INTEGER,\n"
234                 "       `newParam1` INTEGER,\n"
235                 "       `newParam2` INTEGER,\n"
236                 "       `newMeta` TEXT,\n"
237                 "       `guessedActor` INTEGER,\n"
238                 "       FOREIGN KEY (`actor`) REFERENCES `actor`(`id`),\n"
239                 "       FOREIGN KEY (`stackNode`) REFERENCES `node`(`id`),\n"
240                 "       FOREIGN KEY (`oldNode`)   REFERENCES `node`(`id`),\n"
241                 "       FOREIGN KEY (`newNode`)   REFERENCES `node`(`id`)\n"
242                 ");\n"
243                 "CREATE INDEX IF NOT EXISTS `actionActor` ON `action`(`actor`);\n"
244                 "CREATE INDEX IF NOT EXISTS `actionTimestamp` ON `action`(`timestamp`);\n",
245                 NULL, NULL, NULL));
246         verbosestream << "SQL Rollback: SQLite3 database structure was created" << std::endl;
247
248         return true;
249 }
250
251
252 void RollbackManager::initDatabase()
253 {
254         verbosestream << "RollbackManager: Database connection setup" << std::endl;
255
256         bool needsCreate = !fs::PathExists(database_path);
257         SQLOK(sqlite3_open_v2(database_path.c_str(), &db,
258                         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL));
259
260         if (needsCreate) {
261                 createTables();
262         }
263
264         SQLOK(sqlite3_prepare_v2(db,
265                 "INSERT INTO `action` (\n"
266                 "       `actor`, `timestamp`, `type`,\n"
267                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,\n"
268                 "       `x`, `y`, `z`,\n"
269                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
270                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
271                 "       `guessedActor`\n"
272                 ") VALUES (\n"
273                 "       ?, ?, ?,\n"
274                 "       ?, ?, ?, ?, ?, ?,\n"
275                 "       ?, ?, ?,\n"
276                 "       ?, ?, ?, ?,\n"
277                 "       ?, ?, ?, ?,\n"
278                 "       ?"
279                 ");",
280                 -1, &stmt_insert, NULL));
281
282         SQLOK(sqlite3_prepare_v2(db,
283                 "REPLACE INTO `action` (\n"
284                 "       `actor`, `timestamp`, `type`,\n"
285                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,\n"
286                 "       `x`, `y`, `z`,\n"
287                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
288                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
289                 "       `guessedActor`, `id`\n"
290                 ") VALUES (\n"
291                 "       ?, ?, ?,\n"
292                 "       ?, ?, ?, ?, ?, ?,\n"
293                 "       ?, ?, ?,\n"
294                 "       ?, ?, ?, ?,\n"
295                 "       ?, ?, ?, ?,\n"
296                 "       ?, ?\n"
297                 ");",
298                 -1, &stmt_replace, NULL));
299
300         SQLOK(sqlite3_prepare_v2(db,
301                 "SELECT\n"
302                 "       `actor`, `timestamp`, `type`,\n"
303                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n"
304                 "       `x`, `y`, `z`,\n"
305                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
306                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
307                 "       `guessedActor`\n"
308                 " FROM `action`\n"
309                 " WHERE `timestamp` >= ?\n"
310                 " ORDER BY `timestamp` DESC, `id` DESC",
311                 -1, &stmt_select, NULL));
312
313         SQLOK(sqlite3_prepare_v2(db,
314                 "SELECT\n"
315                 "       `actor`, `timestamp`, `type`,\n"
316                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n"
317                 "       `x`, `y`, `z`,\n"
318                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
319                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
320                 "       `guessedActor`\n"
321                 "FROM `action`\n"
322                 "WHERE `timestamp` >= ?\n"
323                 "       AND `x` IS NOT NULL\n"
324                 "       AND `y` IS NOT NULL\n"
325                 "       AND `z` IS NOT NULL\n"
326                 "       AND `x` BETWEEN ? AND ?\n"
327                 "       AND `y` BETWEEN ? AND ?\n"
328                 "       AND `z` BETWEEN ? AND ?\n"
329                 "ORDER BY `timestamp` DESC, `id` DESC\n"
330                 "LIMIT 0,?",
331                 -1, &stmt_select_range, NULL));
332
333         SQLOK(sqlite3_prepare_v2(db,
334                 "SELECT\n"
335                 "       `actor`, `timestamp`, `type`,\n"
336                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n"
337                 "       `x`, `y`, `z`,\n"
338                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
339                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
340                 "       `guessedActor`\n"
341                 "FROM `action`\n"
342                 "WHERE `timestamp` >= ?\n"
343                 "       AND `actor` = ?\n"
344                 "ORDER BY `timestamp` DESC, `id` DESC\n",
345                 -1, &stmt_select_withActor, NULL));
346
347         SQLOK(sqlite3_prepare_v2(db, "SELECT `id`, `name` FROM `actor`",
348                         -1, &stmt_knownActor_select, NULL));
349
350         SQLOK(sqlite3_prepare_v2(db, "INSERT INTO `actor` (`name`) VALUES (?)",
351                         -1, &stmt_knownActor_insert, NULL));
352
353         SQLOK(sqlite3_prepare_v2(db, "SELECT `id`, `name` FROM `node`",
354                         -1, &stmt_knownNode_select, NULL));
355
356         SQLOK(sqlite3_prepare_v2(db, "INSERT INTO `node` (`name`) VALUES (?)",
357                         -1, &stmt_knownNode_insert, NULL));
358
359         verbosestream << "SQL prepared statements setup correctly" << std::endl;
360
361         while (sqlite3_step(stmt_knownActor_select) == SQLITE_ROW) {
362                 registerNewActor(
363                         sqlite3_column_int(stmt_knownActor_select, 0),
364                         reinterpret_cast<const char *>(sqlite3_column_text(stmt_knownActor_select, 1))
365                 );
366         }
367         SQLOK(sqlite3_reset(stmt_knownActor_select));
368
369         while (sqlite3_step(stmt_knownNode_select) == SQLITE_ROW) {
370                 registerNewNode(
371                         sqlite3_column_int(stmt_knownNode_select, 0),
372                         reinterpret_cast<const char *>(sqlite3_column_text(stmt_knownNode_select, 1))
373                 );
374         }
375         SQLOK(sqlite3_reset(stmt_knownNode_select));
376 }
377
378
379 bool RollbackManager::registerRow(const ActionRow & row)
380 {
381         sqlite3_stmt * stmt_do = (row.id) ? stmt_replace : stmt_insert;
382
383         bool nodeMeta = false;
384
385         SQLOK(sqlite3_bind_int  (stmt_do, 1, row.actor));
386         SQLOK(sqlite3_bind_int64(stmt_do, 2, row.timestamp));
387         SQLOK(sqlite3_bind_int  (stmt_do, 3, row.type));
388
389         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
390                 const std::string & loc = row.location;
391                 nodeMeta = (loc.substr(0, 9) == "nodemeta:");
392
393                 SQLOK(sqlite3_bind_text(stmt_do, 4, row.list.c_str(), row.list.size(), NULL));
394                 SQLOK(sqlite3_bind_int (stmt_do, 5, row.index));
395                 SQLOK(sqlite3_bind_int (stmt_do, 6, row.add));
396                 SQLOK(sqlite3_bind_int (stmt_do, 7, row.stack.id));
397                 SQLOK(sqlite3_bind_int (stmt_do, 8, row.stack.count));
398                 SQLOK(sqlite3_bind_int (stmt_do, 9, (int) nodeMeta));
399
400                 if (nodeMeta) {
401                         std::string::size_type p1, p2;
402                         p1 = loc.find(':') + 1;
403                         p2 = loc.find(',');
404                         std::string x = loc.substr(p1, p2 - p1);
405                         p1 = p2 + 1;
406                         p2 = loc.find(',', p1);
407                         std::string y = loc.substr(p1, p2 - p1);
408                         std::string z = loc.substr(p2 + 1);
409                         SQLOK(sqlite3_bind_int(stmt_do, 10, atoi(x.c_str())));
410                         SQLOK(sqlite3_bind_int(stmt_do, 11, atoi(y.c_str())));
411                         SQLOK(sqlite3_bind_int(stmt_do, 12, atoi(z.c_str())));
412                 }
413         } else {
414                 SQLOK(sqlite3_bind_null(stmt_do, 4));
415                 SQLOK(sqlite3_bind_null(stmt_do, 5));
416                 SQLOK(sqlite3_bind_null(stmt_do, 6));
417                 SQLOK(sqlite3_bind_null(stmt_do, 7));
418                 SQLOK(sqlite3_bind_null(stmt_do, 8));
419                 SQLOK(sqlite3_bind_null(stmt_do, 9));
420         }
421
422         if (row.type == RollbackAction::TYPE_SET_NODE) {
423                 SQLOK(sqlite3_bind_int (stmt_do, 10, row.x));
424                 SQLOK(sqlite3_bind_int (stmt_do, 11, row.y));
425                 SQLOK(sqlite3_bind_int (stmt_do, 12, row.z));
426                 SQLOK(sqlite3_bind_int (stmt_do, 13, row.oldNode));
427                 SQLOK(sqlite3_bind_int (stmt_do, 14, row.oldParam1));
428                 SQLOK(sqlite3_bind_int (stmt_do, 15, row.oldParam2));
429                 SQLOK(sqlite3_bind_text(stmt_do, 16, row.oldMeta.c_str(), row.oldMeta.size(), NULL));
430                 SQLOK(sqlite3_bind_int (stmt_do, 17, row.newNode));
431                 SQLOK(sqlite3_bind_int (stmt_do, 18, row.newParam1));
432                 SQLOK(sqlite3_bind_int (stmt_do, 19, row.newParam2));
433                 SQLOK(sqlite3_bind_text(stmt_do, 20, row.newMeta.c_str(), row.newMeta.size(), NULL));
434                 SQLOK(sqlite3_bind_int (stmt_do, 21, row.guessed ? 1 : 0));
435         } else {
436                 if (!nodeMeta) {
437                         SQLOK(sqlite3_bind_null(stmt_do, 10));
438                         SQLOK(sqlite3_bind_null(stmt_do, 11));
439                         SQLOK(sqlite3_bind_null(stmt_do, 12));
440                 }
441                 SQLOK(sqlite3_bind_null(stmt_do, 13));
442                 SQLOK(sqlite3_bind_null(stmt_do, 14));
443                 SQLOK(sqlite3_bind_null(stmt_do, 15));
444                 SQLOK(sqlite3_bind_null(stmt_do, 16));
445                 SQLOK(sqlite3_bind_null(stmt_do, 17));
446                 SQLOK(sqlite3_bind_null(stmt_do, 18));
447                 SQLOK(sqlite3_bind_null(stmt_do, 19));
448                 SQLOK(sqlite3_bind_null(stmt_do, 20));
449                 SQLOK(sqlite3_bind_null(stmt_do, 21));
450         }
451
452         if (row.id) {
453                 SQLOK(sqlite3_bind_int(stmt_do, 22, row.id));
454         }
455
456         int written = sqlite3_step(stmt_do);
457
458         SQLOK(sqlite3_reset(stmt_do));
459
460         return written == SQLITE_DONE;
461 }
462
463
464 const std::list<ActionRow> RollbackManager::actionRowsFromSelect(sqlite3_stmt* stmt)
465 {
466         std::list<ActionRow> rows;
467         const unsigned char * text;
468         size_t size;
469
470         while (sqlite3_step(stmt) == SQLITE_ROW) {
471                 ActionRow row;
472
473                 row.actor     = sqlite3_column_int  (stmt, 0);
474                 row.timestamp = sqlite3_column_int64(stmt, 1);
475                 row.type      = sqlite3_column_int  (stmt, 2);
476
477                 if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
478                         text = sqlite3_column_text (stmt, 3);
479                         size = sqlite3_column_bytes(stmt, 3);
480                         row.list        = std::string(reinterpret_cast<const char*>(text), size);
481                         row.index       = sqlite3_column_int(stmt, 4);
482                         row.add         = sqlite3_column_int(stmt, 5);
483                         row.stack.id    = sqlite3_column_int(stmt, 6);
484                         row.stack.count = sqlite3_column_int(stmt, 7);
485                         row.nodeMeta    = sqlite3_column_int(stmt, 8);
486                 }
487
488                 if (row.type == RollbackAction::TYPE_SET_NODE || row.nodeMeta) {
489                         row.x = sqlite3_column_int(stmt,  9);
490                         row.y = sqlite3_column_int(stmt, 10);
491                         row.z = sqlite3_column_int(stmt, 11);
492                 }
493
494                 if (row.type == RollbackAction::TYPE_SET_NODE) {
495                         row.oldNode   = sqlite3_column_int(stmt, 12);
496                         row.oldParam1 = sqlite3_column_int(stmt, 13);
497                         row.oldParam2 = sqlite3_column_int(stmt, 14);
498                         text = sqlite3_column_text (stmt, 15);
499                         size = sqlite3_column_bytes(stmt, 15);
500                         row.oldMeta   = std::string(reinterpret_cast<const char*>(text), size);
501                         row.newNode   = sqlite3_column_int(stmt, 16);
502                         row.newParam1 = sqlite3_column_int(stmt, 17);
503                         row.newParam2 = sqlite3_column_int(stmt, 18);
504                         text = sqlite3_column_text(stmt, 19);
505                         size = sqlite3_column_bytes(stmt, 19);
506                         row.newMeta   = std::string(reinterpret_cast<const char*>(text), size);
507                         row.guessed   = sqlite3_column_int(stmt, 20);
508                 }
509
510                 if (row.nodeMeta) {
511                         row.location = "nodemeta:";
512                         row.location += itos(row.x);
513                         row.location += ',';
514                         row.location += itos(row.y);
515                         row.location += ',';
516                         row.location += itos(row.z);
517                 } else {
518                         row.location = getActorName(row.actor);
519                 }
520
521                 rows.push_back(row);
522         }
523
524         SQLOK(sqlite3_reset(stmt));
525
526         return rows;
527 }
528
529
530 ActionRow RollbackManager::actionRowFromRollbackAction(const RollbackAction & action)
531 {
532         ActionRow row;
533
534         row.id        = 0;
535         row.actor     = getActorId(action.actor);
536         row.timestamp = action.unix_time;
537         row.type      = action.type;
538
539         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
540                 row.location = action.inventory_location;
541                 row.list     = action.inventory_list;
542                 row.index    = action.inventory_index;
543                 row.add      = action.inventory_add;
544                 row.stack    = action.inventory_stack;
545                 row.stack.id = getNodeId(row.stack.name);
546         } else {
547                 row.x         = action.p.X;
548                 row.y         = action.p.Y;
549                 row.z         = action.p.Z;
550                 row.oldNode   = getNodeId(action.n_old.name);
551                 row.oldParam1 = action.n_old.param1;
552                 row.oldParam2 = action.n_old.param2;
553                 row.oldMeta   = action.n_old.meta;
554                 row.newNode   = getNodeId(action.n_new.name);
555                 row.newParam1 = action.n_new.param1;
556                 row.newParam2 = action.n_new.param2;
557                 row.newMeta   = action.n_new.meta;
558                 row.guessed   = action.actor_is_guess;
559         }
560
561         return row;
562 }
563
564
565 const std::list<RollbackAction> RollbackManager::rollbackActionsFromActionRows(
566                 const std::list<ActionRow> & rows)
567 {
568         std::list<RollbackAction> actions;
569
570         for (std::list<ActionRow>::const_iterator it = rows.begin();
571                         it != rows.end(); ++it) {
572                 RollbackAction action;
573                 action.actor     = (it->actor) ? getActorName(it->actor) : "";
574                 action.unix_time = it->timestamp;
575                 action.type      = static_cast<RollbackAction::Type>(it->type);
576
577                 switch (action.type) {
578                 case RollbackAction::TYPE_MODIFY_INVENTORY_STACK:
579                         action.inventory_location = it->location.c_str();
580                         action.inventory_list     = it->list;
581                         action.inventory_index    = it->index;
582                         action.inventory_add      = it->add;
583                         action.inventory_stack    = it->stack;
584                         if (action.inventory_stack.name.empty()) {
585                                 action.inventory_stack.name = getNodeName(it->stack.id);
586                         }
587                         break;
588
589                 case RollbackAction::TYPE_SET_NODE:
590                         action.p            = v3s16(it->x, it->y, it->z);
591                         action.n_old.name   = getNodeName(it->oldNode);
592                         action.n_old.param1 = it->oldParam1;
593                         action.n_old.param2 = it->oldParam2;
594                         action.n_old.meta   = it->oldMeta;
595                         action.n_new.name   = getNodeName(it->newNode);
596                         action.n_new.param1 = it->newParam1;
597                         action.n_new.param2 = it->newParam2;
598                         action.n_new.meta   = it->newMeta;
599                         break;
600
601                 default:
602                         throw ("W.T.F.");
603                         break;
604                 }
605
606                 actions.push_back(action);
607         }
608
609         return actions;
610 }
611
612
613 const std::list<ActionRow> RollbackManager::getRowsSince(time_t firstTime, const std::string & actor)
614 {
615         sqlite3_stmt *stmt_stmt = actor.empty() ? stmt_select : stmt_select_withActor;
616         sqlite3_bind_int64(stmt_stmt, 1, firstTime);
617
618         if (!actor.empty()) {
619                 sqlite3_bind_int(stmt_stmt, 2, getActorId(actor));
620         }
621
622         const std::list<ActionRow> & rows = actionRowsFromSelect(stmt_stmt);
623         sqlite3_reset(stmt_stmt);
624
625         return rows;
626 }
627
628
629 const std::list<ActionRow> RollbackManager::getRowsSince_range(
630                 time_t start_time, v3s16 p, int range, int limit)
631 {
632
633         sqlite3_bind_int64(stmt_select_range, 1, start_time);
634         sqlite3_bind_int  (stmt_select_range, 2, static_cast<int>(p.X - range));
635         sqlite3_bind_int  (stmt_select_range, 3, static_cast<int>(p.X + range));
636         sqlite3_bind_int  (stmt_select_range, 4, static_cast<int>(p.Y - range));
637         sqlite3_bind_int  (stmt_select_range, 5, static_cast<int>(p.Y + range));
638         sqlite3_bind_int  (stmt_select_range, 6, static_cast<int>(p.Z - range));
639         sqlite3_bind_int  (stmt_select_range, 7, static_cast<int>(p.Z + range));
640         sqlite3_bind_int  (stmt_select_range, 8, limit);
641
642         const std::list<ActionRow> & rows = actionRowsFromSelect(stmt_select_range);
643         sqlite3_reset(stmt_select_range);
644
645         return rows;
646 }
647
648
649 const std::list<RollbackAction> RollbackManager::getActionsSince_range(
650                 time_t start_time, v3s16 p, int range, int limit)
651 {
652         return rollbackActionsFromActionRows(getRowsSince_range(start_time, p, range, limit));
653 }
654
655
656 const std::list<RollbackAction> RollbackManager::getActionsSince(
657                 time_t start_time, const std::string & actor)
658 {
659         return rollbackActionsFromActionRows(getRowsSince(start_time, actor));
660 }
661
662
663 void RollbackManager::migrate(const std::string & file_path)
664 {
665         std::cout << "Migrating from rollback.txt to rollback.sqlite." << std::endl;
666
667         std::ifstream fh(file_path.c_str(), std::ios::in | std::ios::ate);
668         if (!fh.good()) {
669                 throw FileNotGoodException("Unable to open rollback.txt");
670         }
671
672         std::streampos file_size = fh.tellg();
673
674         if (file_size > 10) {
675                 errorstream << "Empty rollback log." << std::endl;
676                 return;
677         }
678
679         fh.seekg(0);
680
681         std::string bit;
682         int i = 0;
683         int id = 1;
684         time_t start = time(0);
685         time_t t = start;
686         sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
687         do {
688                 ActionRow row;
689
690                 row.id = id;
691
692                 // Get the timestamp
693                 std::getline(fh, bit, ' ');
694                 bit = trim(bit);
695                 if (!atoi(bit.c_str())) {
696                         std::getline(fh, bit);
697                         continue;
698                 }
699                 row.timestamp = atoi(bit.c_str());
700
701                 // Get the actor
702                 row.actor = getActorId(deSerializeJsonString(fh));
703
704                 // Get the action type
705                 std::getline(fh, bit, '[');
706                 std::getline(fh, bit, ' ');
707
708                 if (bit == "modify_inventory_stack") {
709                         row.type = RollbackAction::TYPE_MODIFY_INVENTORY_STACK;
710                         row.location = trim(deSerializeJsonString(fh));
711                         std::getline(fh, bit, ' ');
712                         row.list     = trim(deSerializeJsonString(fh));
713                         std::getline(fh, bit, ' ');
714                         std::getline(fh, bit, ' ');
715                         row.index    = atoi(trim(bit).c_str());
716                         std::getline(fh, bit, ' ');
717                         row.add      = (int)(trim(bit) == "add");
718                         row.stack.deSerialize(deSerializeJsonString(fh));
719                         row.stack.id = getNodeId(row.stack.name);
720                         std::getline(fh, bit);
721                 } else if (bit == "set_node") {
722                         row.type = RollbackAction::TYPE_SET_NODE;
723                         std::getline(fh, bit, '(');
724                         std::getline(fh, bit, ',');
725                         row.x       = atoi(trim(bit).c_str());
726                         std::getline(fh, bit, ',');
727                         row.y       = atoi(trim(bit).c_str());
728                         std::getline(fh, bit, ')');
729                         row.z       = atoi(trim(bit).c_str());
730                         std::getline(fh, bit, ' ');
731                         row.oldNode = getNodeId(trim(deSerializeJsonString(fh)));
732                         std::getline(fh, bit, ' ');
733                         std::getline(fh, bit, ' ');
734                         row.oldParam1 = atoi(trim(bit).c_str());
735                         std::getline(fh, bit, ' ');
736                         row.oldParam2 = atoi(trim(bit).c_str());
737                         row.oldMeta   = trim(deSerializeJsonString(fh));
738                         std::getline(fh, bit, ' ');
739                         row.newNode   = getNodeId(trim(deSerializeJsonString(fh)));
740                         std::getline(fh, bit, ' ');
741                         std::getline(fh, bit, ' ');
742                         row.newParam1 = atoi(trim(bit).c_str());
743                         std::getline(fh, bit, ' ');
744                         row.newParam2 = atoi(trim(bit).c_str());
745                         row.newMeta   = trim(deSerializeJsonString(fh));
746                         std::getline(fh, bit, ' ');
747                         std::getline(fh, bit, ' ');
748                         std::getline(fh, bit);
749                         row.guessed = (int)(trim(bit) == "actor_is_guess");
750                 } else {
751                         errorstream << "Unrecognized rollback action type \""
752                                 << bit << "\"!" << std::endl;
753                         continue;
754                 }
755
756                 registerRow(row);
757                 ++i;
758
759                 if (time(0) - t >= 1) {
760                         sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
761                         t = time(0);
762                         std::cout
763                                 << " Done: " << static_cast<int>((static_cast<float>(fh.tellg()) / static_cast<float>(file_size)) * 100) << "%"
764                                 << " Speed: " << i / (t - start) << "/second     \r" << std::flush;
765                         sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
766                 }
767         } while (fh.good());
768
769         std::cout
770                 << " Done: 100%                                   " << std::endl
771                 << "Now you can delete the old rollback.txt file." << std::endl;
772 }
773
774
775 // Get nearness factor for subject's action for this action
776 // Return value: 0 = impossible, >0 = factor
777 float RollbackManager::getSuspectNearness(bool is_guess, v3s16 suspect_p,
778                 time_t suspect_t, v3s16 action_p, time_t action_t)
779 {
780         // Suspect cannot cause things in the past
781         if (action_t < suspect_t) {
782                 return 0;        // 0 = cannot be
783         }
784         // Start from 100
785         int f = 100;
786         // Distance (1 node = -x points)
787         f -= POINTS_PER_NODE * intToFloat(suspect_p, 1).getDistanceFrom(intToFloat(action_p, 1));
788         // Time (1 second = -x points)
789         f -= 1 * (action_t - suspect_t);
790         // If is a guess, halve the points
791         if (is_guess) {
792                 f *= 0.5;
793         }
794         // Limit to 0
795         if (f < 0) {
796                 f = 0;
797         }
798         return f;
799 }
800
801
802 void RollbackManager::reportAction(const RollbackAction &action_)
803 {
804         // Ignore if not important
805         if (!action_.isImportant(gamedef)) {
806                 return;
807         }
808
809         RollbackAction action = action_;
810         action.unix_time = time(0);
811
812         // Figure out actor
813         action.actor = current_actor;
814         action.actor_is_guess = current_actor_is_guess;
815
816         if (action.actor.empty()) { // If actor is not known, find out suspect or cancel
817                 v3s16 p;
818                 if (!action.getPosition(&p)) {
819                         return;
820                 }
821
822                 action.actor = getSuspect(p, 83, 1);
823                 if (action.actor.empty()) {
824                         return;
825                 }
826
827                 action.actor_is_guess = true;
828         }
829
830         addAction(action);
831 }
832
833 std::string RollbackManager::getActor()
834 {
835         return current_actor;
836 }
837
838 bool RollbackManager::isActorGuess()
839 {
840         return current_actor_is_guess;
841 }
842
843 void RollbackManager::setActor(const std::string & actor, bool is_guess)
844 {
845         current_actor = actor;
846         current_actor_is_guess = is_guess;
847 }
848
849 std::string RollbackManager::getSuspect(v3s16 p, float nearness_shortcut,
850                 float min_nearness)
851 {
852         if (current_actor != "") {
853                 return current_actor;
854         }
855         int cur_time = time(0);
856         time_t first_time = cur_time - (100 - min_nearness);
857         RollbackAction likely_suspect;
858         float likely_suspect_nearness = 0;
859         for (std::list<RollbackAction>::const_reverse_iterator
860              i = action_latest_buffer.rbegin();
861              i != action_latest_buffer.rend(); i++) {
862                 if (i->unix_time < first_time) {
863                         break;
864                 }
865                 if (i->actor == "") {
866                         continue;
867                 }
868                 // Find position of suspect or continue
869                 v3s16 suspect_p;
870                 if (!i->getPosition(&suspect_p)) {
871                         continue;
872                 }
873                 float f = getSuspectNearness(i->actor_is_guess, suspect_p,
874                                              i->unix_time, p, cur_time);
875                 if (f >= min_nearness && f > likely_suspect_nearness) {
876                         likely_suspect_nearness = f;
877                         likely_suspect = *i;
878                         if (likely_suspect_nearness >= nearness_shortcut) {
879                                 break;
880                         }
881                 }
882         }
883         // No likely suspect was found
884         if (likely_suspect_nearness == 0) {
885                 return "";
886         }
887         // Likely suspect was found
888         return likely_suspect.actor;
889 }
890
891
892 void RollbackManager::flush()
893 {
894         sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
895
896         std::list<RollbackAction>::const_iterator iter;
897
898         for (iter  = action_todisk_buffer.begin();
899                         iter != action_todisk_buffer.end();
900                         iter++) {
901                 if (iter->actor == "") {
902                         continue;
903                 }
904
905                 registerRow(actionRowFromRollbackAction(*iter));
906         }
907
908         sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
909         action_todisk_buffer.clear();
910 }
911
912
913 void RollbackManager::addAction(const RollbackAction & action)
914 {
915         action_todisk_buffer.push_back(action);
916         action_latest_buffer.push_back(action);
917
918         // Flush to disk sometimes
919         if (action_todisk_buffer.size() >= 500) {
920                 flush();
921         }
922 }
923
924 std::list<RollbackAction> RollbackManager::getEntriesSince(time_t first_time)
925 {
926         flush();
927         return getActionsSince(first_time);
928 }
929
930 std::list<RollbackAction> RollbackManager::getNodeActors(v3s16 pos, int range,
931                 time_t seconds, int limit)
932 {
933         time_t cur_time = time(0);
934         time_t first_time = cur_time - seconds;
935
936         return getActionsSince_range(first_time, pos, range, limit);
937 }
938
939 std::list<RollbackAction> RollbackManager::getRevertActions(
940                 const std::string &actor_filter,
941                 time_t seconds)
942 {
943         time_t cur_time = time(0);
944         time_t first_time = cur_time - seconds;
945
946         flush();
947
948         return getActionsSince(first_time, actor_filter);
949 }
950