rollback.cpp 35 KB

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