· 7 years ago · Sep 22, 2018, 08:28 AM
1From d03b95561a3b3c839b09c8f7408d8c173ddb9f93 Mon Sep 17 00:00:00 2001
2From: monkey <monkey@monkey.(none)>
3Date: Sun, 19 Aug 2012 02:56:15 -0300
4Subject: [PATCH 1/4] basic sqlite3 saving
5
6---
7 CMakeLists.txt | 19 ++
8 savedb.cpp | 613 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 savedb.h | 43 ++++
10 3 files changed, 675 insertions(+), 0 deletions(-)
11 create mode 100644 CMakeLists.txt
12 create mode 100644 savedb.cpp
13 create mode 100644 savedb.h
14
15diff --git a/CMakeLists.txt b/CMakeLists.txt
16new file mode 100644
17index 0000000..a8bcd69
18--- /dev/null
19+++ b/CMakeLists.txt
20@@ -0,0 +1,19 @@
21+cmake_minimum_required (VERSION 2.6)
22+
23+project (Cataclysm)
24+
25+file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" )
26+file(GLOB HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/*.h" )
27+set(LIBS ncurses)
28+
29+############ sqlite3
30+add_definitions( -DUSE_SAVEDB )
31+set(LIBS ${LIBS} sqlite3)
32+
33+
34+#### add_definitions( -pg ) # profile
35+
36+add_executable(cataclysm ${SOURCES} ${HEADERS})
37+target_link_libraries(cataclysm ${LIBS})
38+
39+
40diff --git a/savedb.cpp b/savedb.cpp
41new file mode 100644
42index 0000000..d425186
43--- /dev/null
44+++ b/savedb.cpp
45@@ -0,0 +1,613 @@
46+
47+#include <assert.h>
48+#include <stdlib.h>
49+#include <string.h> // memcpy
50+
51+#include <sqlite3.h>
52+#include "game.h"
53+#include "savedb.h"
54+
55+#include "mapdata.h"
56+#include "map.h"
57+
58+SaveDB* SaveDB::instance = 0;
59+
60+SaveDB::SaveDB()
61+ : db(0)
62+ ,saveSubmap_stmt(0), loadSubmap_stmt(0)
63+ ,saveItem_stmt(0), loadItem_stmt(0),deleteItems_stmt(0)
64+ ,saveSpawn_stmt(0), loadSpawn_stmt(0), deleteSpawns_stmt(0)
65+ ,saveVehicle_stmt(0), loadVehicle_stmt(0), deleteVehicles_stmt(0)
66+{
67+}
68+
69+bool SaveDB::createTables()
70+{
71+ assert(db);
72+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS submaps \
73+ (x INTEGER, y INTEGER, z INTEGER, turn INTEGER, \
74+ terrain BLOB, \
75+ radiation BLOB, \
76+ traps BLOB, \
77+ fields BLOB, \
78+ computer BLOB, \
79+ PRIMARY KEY(x,y,z))",0,0,0)) {
80+ // implicit index on primary key
81+ fprintf(stderr, "Can't create table submaps: %s\n", sqlite3_errmsg(db));
82+ sqlite3_close(db);
83+ return false;
84+ }
85+ // items
86+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS items (x INTEGER, y INTEGER, z INTEGER, i INTEGER, j INTEGER, type INTEGER, data BLOB, seq INTEGER, inside INTEGER)",0,0,0)) {
87+ // implicit index on primary key
88+ fprintf(stderr, "Can't create table items: %s\n", sqlite3_errmsg(db));
89+ sqlite3_close(db);
90+ return false;
91+ }
92+ if (sqlite3_exec(db,"CREATE INDEX IF NOT EXISTS items_idx ON items (x,y,z)",0,0,0)) {
93+ // implicit index on primary key
94+ fprintf(stderr, "Can't create index items: %s\n", sqlite3_errmsg(db));
95+ sqlite3_close(db);
96+ return false;
97+ }
98+ // spawns
99+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS spawns \
100+ (x INTEGER,y INTEGER, z INTEGER, \
101+ name TEXT, type INTEGER, \
102+ count INTEGER, \
103+ posx INTEGER, posy INTEGER, \
104+ faction INTEGER, mission INTEGER, \
105+ friendly INTEGER)",0,0,0)) {
106+ // implicit index on primary key
107+ fprintf(stderr, "Can't create table spawns: %s\n", sqlite3_errmsg(db));
108+ sqlite3_close(db);
109+ return false;
110+ }
111+ if (sqlite3_exec(db,"CREATE INDEX IF NOT EXISTS spawns_idx ON spawns (x,y,z)",0,0,0)) {
112+ // implicit index on primary key
113+ fprintf(stderr, "Can't create index spawns: %s\n", sqlite3_errmsg(db));
114+ sqlite3_close(db);
115+ return false;
116+ }
117+ // vehicles
118+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS vehicles (x INTEGER, y INTEGER, z INTEGER, type INTEGER, data BLOB)",0,0,0)) {
119+ // implicit index on primary key
120+ fprintf(stderr, "Can't create table vehicles: %s\n", sqlite3_errmsg(db));
121+ sqlite3_close(db);
122+ return false;
123+ }
124+ if (sqlite3_exec(db,"CREATE INDEX IF NOT EXISTS vehicles_idx ON items (x,y,z)",0,0,0)) {
125+ // implicit index on primary key
126+ fprintf(stderr, "Can't create index vehicles: %s\n", sqlite3_errmsg(db));
127+ sqlite3_close(db);
128+ return false;
129+ }
130+
131+ // types, these are not used in game
132+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS itypes (type INTEGER, name TEXT, PRIMARY KEY(type))",0,0,0)) {
133+ // implicit index on primary key
134+ fprintf(stderr, "Can't create table itypes: %s\n", sqlite3_errmsg(db));
135+ sqlite3_close(db);
136+ return false;
137+ }
138+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS mtypes (type INTEGER, name TEXT, PRIMARY KEY(type))",0,0,0)) {
139+ // implicit index on primary key
140+ fprintf(stderr, "Can't create table itypes: %s\n", sqlite3_errmsg(db));
141+ sqlite3_close(db);
142+ return false;
143+ }
144+ if (sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS vtypes (type INTEGER, name TEXT, PRIMARY KEY(type))",0,0,0)) {
145+ // implicit index on primary key
146+ fprintf(stderr, "Can't create table vtypes: %s\n", sqlite3_errmsg(db));
147+ sqlite3_close(db);
148+ return false;
149+ }
150+
151+
152+ return true;
153+}
154+
155+bool SaveDB::createStatements()
156+{
157+ assert(db);
158+ // submaps
159+ if (sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO submaps (x,y,z,turn,terrain,radiation,traps,fields,computer) VALUES (?,?,?,?, ?,?,?,?,?)", -1, &saveSubmap_stmt, 0)){
160+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
161+ sqlite3_close(db);
162+ return false;
163+ }
164+ if (sqlite3_prepare_v2(db, "SELECT turn,terrain,radiation,traps,fields,computer FROM submaps WHERE x = ? AND y = ? AND z = ?", -1, &loadSubmap_stmt, 0)) {
165+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
166+ sqlite3_close(db);
167+ return false;
168+ }
169+ // items
170+ if (sqlite3_prepare_v2(db, "INSERT INTO items (x,y,z,i,j,type,data,seq,inside) VALUES (?,?,?,?,?, ?,?, ?,?)", -1, &saveItem_stmt, 0)) {
171+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
172+ sqlite3_close(db);
173+ return false;
174+ }
175+ if (sqlite3_prepare_v2(db, "SELECT i,j,data,inside FROM items WHERE x = ? AND y = ? AND z = ? ORDER BY seq ASC", -1, &loadItem_stmt, 0)) {
176+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
177+ sqlite3_close(db);
178+ return false;
179+ }
180+ if (sqlite3_prepare_v2(db, "DELETE FROM items WHERE x = ? AND y = ? AND z = ?", -1, &deleteItems_stmt, 0)) {
181+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
182+ sqlite3_close(db);
183+ return false;
184+ }
185+ // spawns
186+ if (sqlite3_prepare_v2(db, "INSERT INTO spawns (x,y,z,name,type,count,posx,posy,faction,mission,friendly) VALUES (?,?,?,?,?,?,?,?,?,?,?)", -1, &saveSpawn_stmt, 0)) {
187+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
188+ sqlite3_close(db);
189+ return false;
190+ }
191+ if (sqlite3_prepare_v2(db, "SELECT name,type,count,posx,posy,faction,mission,friendly FROM spawns WHERE x = ? AND y = ? AND z = ?", -1, &loadSpawn_stmt, 0)) {
192+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
193+ sqlite3_close(db);
194+ return false;
195+ }
196+ if (sqlite3_prepare_v2(db, "DELETE FROM spawns WHERE x = ? AND y = ? AND z = ?", -1, &deleteSpawns_stmt, 0)) {
197+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
198+ sqlite3_close(db);
199+ return false;
200+ }
201+ // vehicles
202+ if (sqlite3_prepare_v2(db, "INSERT INTO vehicles (x,y,z,type,data) VALUES (?,?,?,?,?)", -1, &saveVehicle_stmt, 0)) {
203+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
204+ sqlite3_close(db);
205+ return false;
206+ }
207+ if (sqlite3_prepare_v2(db, "SELECT data FROM vehicles WHERE x = ? AND y = ? AND z = ?", -1, &loadVehicle_stmt, 0)) {
208+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
209+ sqlite3_close(db);
210+ return false;
211+ }
212+ if (sqlite3_prepare_v2(db, "DELETE FROM vehicles WHERE x = ? AND y = ? AND z = ?", -1, &deleteVehicles_stmt, 0)) {
213+ fprintf(stderr, "Can't prepare stmt: %s\n", sqlite3_errmsg(db));
214+ sqlite3_close(db);
215+ return false;
216+ }
217+
218+ return true;
219+}
220+
221+bool SaveDB::init(game* g)
222+{
223+ assert(!db);
224+
225+ int rc = sqlite3_open("save/savedb.sqlite3", &db);
226+ if( rc ){
227+ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
228+ sqlite3_close(db);
229+ return false;
230+ }
231+ sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
232+ sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, NULL);
233+
234+ if (!createTables())
235+ return false;
236+
237+ if (!createStatements())
238+ return false;
239+
240+ if (!storeTypes(g))
241+ return false;
242+
243+ return true;
244+}
245+
246+void SaveDB::close()
247+{
248+ if (!db)
249+ return;
250+
251+ sqlite3_finalize(saveSubmap_stmt);
252+ sqlite3_finalize(loadSubmap_stmt);
253+ saveSubmap_stmt = loadSubmap_stmt = 0;
254+
255+ sqlite3_finalize(saveItem_stmt);
256+ sqlite3_finalize(loadItem_stmt);
257+ sqlite3_finalize(deleteItems_stmt);
258+ saveItem_stmt = loadItem_stmt = deleteItems_stmt = 0;
259+
260+ sqlite3_finalize(saveSpawn_stmt);
261+ sqlite3_finalize(loadSpawn_stmt);
262+ sqlite3_finalize(deleteSpawns_stmt);
263+ saveSpawn_stmt = loadSpawn_stmt = deleteSpawns_stmt = 0;
264+
265+ sqlite3_exec(db,"vacuum", 0,0,0); // cleanup
266+ sqlite3_close(db);
267+ db = 0;
268+}
269+
270+bool SaveDB::loadSubmap(game* g, int x,int y,int z,int &turn,
271+ submap& smap,
272+ int gridx,int gridy)
273+{
274+ assert(db);
275+ sqlite3_clear_bindings(loadSubmap_stmt);
276+ sqlite3_reset(loadSubmap_stmt);
277+
278+ sqlite3_bind_int(loadSubmap_stmt, 1, x);
279+ sqlite3_bind_int(loadSubmap_stmt, 2, y);
280+ sqlite3_bind_int(loadSubmap_stmt, 3, z);
281+
282+ int rc = 0;
283+ while ((rc = sqlite3_step(loadSubmap_stmt)) == SQLITE_BUSY) ;
284+ // TODO: check error
285+
286+ if (rc != SQLITE_ROW) // no submap stored, returns false to generate one
287+ return false;
288+
289+ smap.active_item_count = 0;
290+ smap.field_count = 0;
291+ smap.comp = computer();
292+ smap.vehicles.clear();
293+
294+ int old_turn = sqlite3_column_int(loadSubmap_stmt,0);
295+ const void* data = sqlite3_column_blob(loadSubmap_stmt, 1);
296+ size_t dataSize = sqlite3_column_bytes(loadSubmap_stmt, 1);
297+ memcpy(smap.ter, data, dataSize);
298+ // radiation
299+ data = sqlite3_column_blob(loadSubmap_stmt, 2);
300+ dataSize = sqlite3_column_bytes(loadSubmap_stmt, 2);
301+ memcpy(smap.rad, data, dataSize);
302+ // traps
303+ data = sqlite3_column_blob(loadSubmap_stmt, 3);
304+ dataSize = sqlite3_column_bytes(loadSubmap_stmt, 3);
305+ memcpy(smap.trp, data, dataSize);
306+ // fields
307+ data = sqlite3_column_blob(loadSubmap_stmt, 4);
308+ dataSize = sqlite3_column_bytes(loadSubmap_stmt, 4);
309+ memcpy(smap.fld, data, dataSize);
310+
311+ // computer
312+ data = sqlite3_column_blob(loadSubmap_stmt, 5);
313+ dataSize = sqlite3_column_bytes(loadSubmap_stmt, 5);
314+ smap.comp.load_data(std::string((const char*)data,dataSize));
315+
316+ sqlite3_bind_blob(saveSubmap_stmt, 8, smap.fld, sizeof(field)*SEEX*SEEY, SQLITE_TRANSIENT);
317+
318+ int turndif = (int(turn) > old_turn ? int(turn) - old_turn : 0);
319+ for (int j = 0; j < SEEY; j++) {
320+ for (int i = 0; i < SEEX; i++) {
321+ smap.itm[i][j].clear();
322+ int radtmp = smap.rad[i][j];
323+ radtmp -= int(turndif / 100); // Radiation slowly decays
324+ if (radtmp < 0)
325+ radtmp = 0;
326+ smap.rad[i][j] = radtmp;
327+
328+ if (smap.fld[i][j].type != 0)
329+ smap.field_count++;
330+ }
331+ }
332+
333+ // load items
334+ sqlite3_clear_bindings(loadItem_stmt);
335+ sqlite3_reset(loadItem_stmt);
336+ sqlite3_bind_int(loadItem_stmt, 1, x);
337+ sqlite3_bind_int(loadItem_stmt, 2, y);
338+ sqlite3_bind_int(loadItem_stmt, 3, z);
339+ while ((rc = sqlite3_step(loadItem_stmt)) == SQLITE_ROW) {
340+ int i = sqlite3_column_int(loadItem_stmt,0);
341+ int j = sqlite3_column_int(loadItem_stmt,1);
342+
343+ const void* data = sqlite3_column_blob(loadItem_stmt, 2);
344+ size_t dataSize = sqlite3_column_bytes(loadItem_stmt, 2);
345+ std::string databuff((const char*)data,dataSize);
346+
347+ int inside = sqlite3_column_int(loadItem_stmt,3);
348+
349+ item it_tmp;
350+ it_tmp.load_info(databuff, g);
351+
352+ if (inside == -1)
353+ smap.itm[i][j].push_back(it_tmp);
354+ else
355+ smap.itm[i][j][inside].put_in(it_tmp);
356+
357+ if (it_tmp.active)
358+ smap.active_item_count++;
359+ }
360+
361+ // load spawns
362+ sqlite3_clear_bindings(loadSpawn_stmt);
363+ sqlite3_reset(loadSpawn_stmt);
364+ sqlite3_bind_int(loadSpawn_stmt, 1, x);
365+ sqlite3_bind_int(loadSpawn_stmt, 2, y);
366+ sqlite3_bind_int(loadSpawn_stmt, 3, z);
367+ while ((rc = sqlite3_step(loadSpawn_stmt)) == SQLITE_ROW) {
368+ std::string spawnname = std::string((const char*)sqlite3_column_text(loadSpawn_stmt,0));
369+ int type = sqlite3_column_int(loadSpawn_stmt,1);
370+ int count = sqlite3_column_int(loadSpawn_stmt,2);
371+ int posx = sqlite3_column_int(loadSpawn_stmt,3);
372+ int posy = sqlite3_column_int(loadSpawn_stmt,4);
373+ int faction = sqlite3_column_int(loadSpawn_stmt,5);
374+ int mission = sqlite3_column_int(loadSpawn_stmt,6);
375+ bool friendly = sqlite3_column_int(loadSpawn_stmt,7) != 0;
376+
377+ spawn_point tmp(mon_id(type), count,
378+ posx, posy,
379+ faction, mission, friendly,
380+ spawnname);
381+ smap.spawns.push_back(tmp);
382+ }
383+
384+ // load vehicles
385+ sqlite3_clear_bindings(loadVehicle_stmt);
386+ sqlite3_reset(loadVehicle_stmt);
387+ sqlite3_bind_int(loadVehicle_stmt, 1, x);
388+ sqlite3_bind_int(loadVehicle_stmt, 2, y);
389+ sqlite3_bind_int(loadVehicle_stmt, 3, z);
390+ while ((rc = sqlite3_step(loadVehicle_stmt)) == SQLITE_ROW) {
391+ vehicle veh(g);
392+ data = sqlite3_column_blob(loadVehicle_stmt, 0);
393+ dataSize = sqlite3_column_bytes(loadVehicle_stmt, 0);
394+
395+ std::istringstream iss(std::string ((const char*)data,dataSize));
396+ veh.load (iss);
397+ veh.smx = gridx;
398+ veh.smy = gridy;
399+ smap.vehicles.push_back(veh);
400+ }
401+
402+ turn = old_turn;
403+ return true;
404+}
405+
406+void SaveDB::saveSubmap(int x,int y,int z,int turn,const submap& smap)
407+{
408+ assert(db);
409+ int rc = 0;
410+
411+ sqlite3_exec(db,"BEGIN TRANSACTION",0,0,0);
412+
413+ computer c = smap.comp;
414+ std::string computer = c.save_data();
415+ sqlite3_clear_bindings(saveSubmap_stmt);
416+ sqlite3_reset(saveSubmap_stmt);
417+ sqlite3_bind_int(saveSubmap_stmt, 1, x);
418+ sqlite3_bind_int(saveSubmap_stmt, 2, y);
419+ sqlite3_bind_int(saveSubmap_stmt, 3, z);
420+ sqlite3_bind_int(saveSubmap_stmt, 4, turn);
421+ sqlite3_bind_blob(saveSubmap_stmt, 5, smap.ter, sizeof(ter_id)*SEEX*SEEY, SQLITE_TRANSIENT);
422+ sqlite3_bind_blob(saveSubmap_stmt, 6, smap.rad, sizeof(int)*SEEX*SEEY, SQLITE_TRANSIENT);
423+ sqlite3_bind_blob(saveSubmap_stmt, 7, smap.trp, sizeof(trap_id)*SEEX*SEEY, SQLITE_TRANSIENT);
424+ sqlite3_bind_blob(saveSubmap_stmt, 8, smap.fld, sizeof(field)*SEEX*SEEY, SQLITE_TRANSIENT);
425+ sqlite3_bind_blob(saveSubmap_stmt, 9, computer.data(), computer.size(), SQLITE_TRANSIENT);
426+ while ((rc = sqlite3_step(saveSubmap_stmt)) == SQLITE_BUSY) ; // other processes can block this
427+ if (rc != SQLITE_DONE) {
428+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
429+ exit(rc);
430+ }
431+
432+ // store items
433+ // clear items from submap @x,y,z
434+ sqlite3_clear_bindings(deleteItems_stmt);
435+ sqlite3_reset(deleteItems_stmt);
436+ sqlite3_bind_int(deleteItems_stmt, 1, x);
437+ sqlite3_bind_int(deleteItems_stmt, 2, y);
438+ sqlite3_bind_int(deleteItems_stmt, 3, z);
439+ while ((rc = sqlite3_step(deleteItems_stmt)) == SQLITE_BUSY) ;
440+ if (rc != SQLITE_DONE) {
441+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
442+ exit(rc);
443+ }
444+
445+ item tmp;
446+ for (int j = 0; j < SEEY; j++) {
447+ for (int i = 0; i < SEEX; i++) {
448+ for (int k = 0;k < smap.itm[i][j].size();++k) {
449+ item tmp = smap.itm[i][j][k];
450+
451+ std::string info = tmp.save_info();
452+ sqlite3_clear_bindings(saveItem_stmt);
453+ sqlite3_reset(saveItem_stmt);
454+ sqlite3_bind_int(saveItem_stmt, 1, x);
455+ sqlite3_bind_int(saveItem_stmt, 2, y);
456+ sqlite3_bind_int(saveItem_stmt, 3, z);
457+ sqlite3_bind_int(saveItem_stmt, 4, i);
458+ sqlite3_bind_int(saveItem_stmt, 5, j);
459+ sqlite3_bind_int(saveItem_stmt, 6, tmp.type->id);
460+ sqlite3_bind_blob(saveItem_stmt, 7, info.data(), info.size(), SQLITE_TRANSIENT);
461+ sqlite3_bind_int(saveItem_stmt, 8, k);
462+ sqlite3_bind_int(saveItem_stmt, 9, -1); // not contained
463+ while ((rc = sqlite3_step(saveItem_stmt)) == SQLITE_BUSY) ; // other processes can block this
464+ if (rc != SQLITE_DONE) {
465+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
466+ exit(rc);
467+ }
468+
469+ for (int l = 0; l < tmp.contents.size(); l++) {
470+ std::string cinfo = tmp.contents[l].save_info();
471+
472+ sqlite3_clear_bindings(saveItem_stmt);
473+ sqlite3_reset(saveItem_stmt);
474+ sqlite3_bind_int(saveItem_stmt, 1, x);
475+ sqlite3_bind_int(saveItem_stmt, 2, y);
476+ sqlite3_bind_int(saveItem_stmt, 3, z);
477+ sqlite3_bind_int(saveItem_stmt, 4, i);
478+ sqlite3_bind_int(saveItem_stmt, 5, j);
479+ sqlite3_bind_int(saveItem_stmt, 6, tmp.contents[l].type->id);
480+ sqlite3_bind_blob(saveItem_stmt, 7, cinfo.data(), cinfo.size(), SQLITE_TRANSIENT);
481+ sqlite3_bind_int(saveItem_stmt, 8, 9999); // add last
482+ sqlite3_bind_int(saveItem_stmt, 9, k);
483+ while ((rc = sqlite3_step(saveItem_stmt)) == SQLITE_BUSY) ; // other processes can block this
484+ if (rc != SQLITE_DONE) {
485+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
486+ exit(rc);
487+ }
488+ }
489+ }
490+ }
491+ }
492+
493+ // spawns
494+ // clear submap spawns
495+ sqlite3_clear_bindings(deleteSpawns_stmt);
496+ sqlite3_reset(deleteSpawns_stmt);
497+ sqlite3_bind_int(deleteSpawns_stmt, 1, x);
498+ sqlite3_bind_int(deleteSpawns_stmt, 2, y);
499+ sqlite3_bind_int(deleteSpawns_stmt, 3, z);
500+ while ((rc = sqlite3_step(deleteSpawns_stmt)) == SQLITE_BUSY) ;
501+ if (rc != SQLITE_DONE) {
502+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
503+ exit(rc);
504+ }
505+ // store
506+ for (std::vector<spawn_point>::const_iterator sIt = smap.spawns.begin(); sIt != smap.spawns.end();++sIt) {
507+ const spawn_point& s = *sIt;
508+ sqlite3_clear_bindings(saveSpawn_stmt);
509+ sqlite3_reset(saveSpawn_stmt);
510+ sqlite3_bind_int(saveSpawn_stmt, 1, x);
511+ sqlite3_bind_int(saveSpawn_stmt, 2, y);
512+ sqlite3_bind_int(saveSpawn_stmt, 3, z);
513+ sqlite3_bind_text(saveSpawn_stmt, 4, s.name.c_str(), s.name.size(), SQLITE_TRANSIENT);
514+ sqlite3_bind_int(saveSpawn_stmt, 5, s.type );
515+ sqlite3_bind_int(saveItem_stmt, 6, s.count);
516+ sqlite3_bind_int(saveItem_stmt, 7, s.posx);
517+ sqlite3_bind_int(saveItem_stmt, 8, s.posy);
518+ sqlite3_bind_int(saveItem_stmt, 9, s.faction_id);
519+ sqlite3_bind_int(saveItem_stmt, 10, s.mission_id);
520+ sqlite3_bind_int(saveItem_stmt, 11, s.friendly);
521+ while ((rc = sqlite3_step(saveSpawn_stmt)) == SQLITE_BUSY) ; // other processes can block this
522+ if (rc != SQLITE_DONE) {
523+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
524+ exit(rc);
525+ }
526+ }
527+ // vehicles
528+ // clear submap vehicles
529+ sqlite3_clear_bindings(deleteVehicles_stmt);
530+ sqlite3_reset(deleteVehicles_stmt);
531+ sqlite3_bind_int(deleteVehicles_stmt, 1, x);
532+ sqlite3_bind_int(deleteVehicles_stmt, 2, y);
533+ sqlite3_bind_int(deleteVehicles_stmt, 3, z);
534+ while ((rc = sqlite3_step(deleteVehicles_stmt)) == SQLITE_BUSY) ;
535+ if (rc != SQLITE_DONE) {
536+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
537+ exit(rc);
538+ }
539+ // store
540+ for (std::vector<vehicle>::const_iterator vIt = smap.vehicles.begin();vIt != smap.vehicles.end();++vIt) {
541+ std::ostringstream oss;
542+ vehicle v = *vIt;
543+ v.save(oss);
544+ std::string data = oss.str();
545+
546+ sqlite3_clear_bindings(saveVehicle_stmt);
547+ sqlite3_reset(saveVehicle_stmt);
548+ sqlite3_bind_int(saveVehicle_stmt, 1, x);
549+ sqlite3_bind_int(saveVehicle_stmt, 2, y);
550+ sqlite3_bind_int(saveVehicle_stmt, 3, z);
551+ sqlite3_bind_int(saveVehicle_stmt, 4, v.type);
552+ sqlite3_bind_text(saveVehicle_stmt, 5, data.data(), data.size(), SQLITE_TRANSIENT);
553+ while ((rc = sqlite3_step(saveVehicle_stmt)) == SQLITE_BUSY) ; // other processes can block this
554+ if (rc != SQLITE_DONE) {
555+ fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
556+ exit(rc);
557+ }
558+ }
559+ sqlite3_exec(db,"END TRANSACTION",0,0,0);
560+}
561+
562+bool SaveDB::storeTypes(game* g)
563+{
564+ sqlite3_stmt* check_stmt;
565+ if (sqlite3_prepare_v2(db, "SELECT 1 FROM itypes", -1, &check_stmt, 0)) {
566+ fprintf(stderr, "Can't check itypes: %s\n", sqlite3_errmsg(db));
567+ sqlite3_close(db);
568+ return false;
569+ }
570+
571+ bool found = false;
572+ if (sqlite3_step(check_stmt) == SQLITE_ROW) found = true;
573+ sqlite3_finalize(check_stmt);
574+
575+ if (found)
576+ return true;
577+
578+ sqlite3_exec(db,"BEGIN TRANSACTION",0,0,0);
579+
580+ // items
581+ sqlite3_stmt* storeItemType_stmt;
582+ if (sqlite3_prepare_v2(db, "INSERT INTO itypes (type,name) VALUES (?,?)", -1, &storeItemType_stmt, 0)){
583+ fprintf(stderr, "Can't create store itypes stmt: %s\n", sqlite3_errmsg(db));
584+ sqlite3_close(db);
585+ return false;
586+ }
587+
588+ for (std::vector <itype*>::const_iterator i = g->itypes.begin();i != g->itypes.end();++i) {
589+ const itype* it = *i;
590+
591+ sqlite3_clear_bindings(storeItemType_stmt);
592+ sqlite3_reset(storeItemType_stmt);
593+
594+ sqlite3_bind_int(storeItemType_stmt,1, it->id);
595+ sqlite3_bind_text(storeItemType_stmt,2, it->name.c_str(),it->name.size(), SQLITE_TRANSIENT);
596+ if (sqlite3_step(storeItemType_stmt) != SQLITE_DONE) {
597+ fprintf(stderr, "Can't store itype: %s\n", sqlite3_errmsg(db));
598+ sqlite3_finalize(storeItemType_stmt);
599+ sqlite3_close(db);
600+ return false;
601+ }
602+ }
603+ sqlite3_finalize(storeItemType_stmt);
604+
605+ // monsters
606+ sqlite3_stmt* storeMonType_stmt;
607+ if (sqlite3_prepare_v2(db, "INSERT INTO mtypes (type,name) VALUES (?,?)", -1, &storeMonType_stmt, 0)){
608+ fprintf(stderr, "Can't create store itypes stmt: %s\n", sqlite3_errmsg(db));
609+ sqlite3_close(db);
610+ return false;
611+ }
612+
613+ for (std::vector <mtype*>::const_iterator i = g->mtypes.begin();i != g->mtypes.end();++i) {
614+ const mtype* it = *i;
615+
616+ sqlite3_clear_bindings(storeMonType_stmt);
617+ sqlite3_reset(storeMonType_stmt);
618+
619+ sqlite3_bind_int(storeMonType_stmt,1, it->id);
620+ sqlite3_bind_text(storeMonType_stmt,2, it->name.c_str(),it->name.size(), SQLITE_TRANSIENT);
621+ if (sqlite3_step(storeMonType_stmt) != SQLITE_DONE) {
622+ fprintf(stderr, "Can't store itype: %s\n", sqlite3_errmsg(db));
623+ sqlite3_finalize(storeMonType_stmt);
624+ sqlite3_close(db);
625+ return false;
626+ }
627+ }
628+ sqlite3_finalize(storeMonType_stmt);
629+
630+ // vehicles
631+ sqlite3_stmt* storeVehType_stmt;
632+ if (sqlite3_prepare_v2(db, "INSERT INTO vtypes (type,name) VALUES (?,?)", -1, &storeVehType_stmt, 0)){
633+ fprintf(stderr, "Can't create store vtypes stmt: %s\n", sqlite3_errmsg(db));
634+ sqlite3_close(db);
635+ return false;
636+ }
637+
638+ for (std::vector <vehicle*>::const_iterator i = g->vtypes.begin();i != g->vtypes.end();++i) {
639+ const vehicle* it = *i;
640+
641+ sqlite3_clear_bindings(storeVehType_stmt);
642+ sqlite3_reset(storeVehType_stmt);
643+
644+ sqlite3_bind_int(storeVehType_stmt,1, it->type);
645+ sqlite3_bind_text(storeVehType_stmt,2, it->name.c_str(),it->name.size(), SQLITE_TRANSIENT);
646+ if (sqlite3_step(storeVehType_stmt) != SQLITE_DONE) {
647+ fprintf(stderr, "Can't store itype: %s\n", sqlite3_errmsg(db));
648+ sqlite3_finalize(storeMonType_stmt);
649+ sqlite3_close(db);
650+ return false;
651+ }
652+ }
653+ sqlite3_finalize(storeVehType_stmt);
654+
655+ sqlite3_exec(db,"END TRANSACTION",0,0,0);
656+ return true;
657+}
658+
659diff --git a/savedb.h b/savedb.h
660new file mode 100644
661index 0000000..262eb47
662--- /dev/null
663+++ b/savedb.h
664@@ -0,0 +1,43 @@
665+
666+#ifndef _SAVEDB_H_
667+#define _SAVEDB_H_
668+
669+class sqlite3;
670+class sqlite3_stmt;
671+class game;
672+struct submap;
673+
674+class SaveDB {
675+ public:
676+
677+ bool init(game* g);
678+ void close();
679+
680+ bool loadSubmap(game* g,int x,int y,int z,int &turn,submap& smap,
681+ int gridx,int gridy);
682+ void saveSubmap(int x,int y,int z,int turn,const submap& smap);
683+
684+ static SaveDB* getInstance() { // singleton
685+ if (!instance)
686+ instance = new SaveDB();
687+ return instance;
688+ }
689+ protected:
690+ SaveDB();
691+
692+ static SaveDB* instance;
693+ sqlite3* db;
694+
695+ sqlite3_stmt* saveSubmap_stmt,*loadSubmap_stmt;
696+ sqlite3_stmt* saveItem_stmt,*loadItem_stmt, *deleteItems_stmt;
697+ sqlite3_stmt* saveSpawn_stmt,*loadSpawn_stmt, *deleteSpawns_stmt;
698+ sqlite3_stmt* saveVehicle_stmt,*loadVehicle_stmt, *deleteVehicles_stmt;
699+
700+ bool createTables();
701+ bool createStatements();
702+
703+ bool storeTypes(game* g);
704+
705+};
706+
707+#endif
708--
7091.7.5.4
710
711
712From 6467a79a0613eff2a8d23a4e28a725db3557cbe0 Mon Sep 17 00:00:00 2001
713From: monkey <monkey@monkey.(none)>
714Date: Sun, 19 Aug 2012 03:00:36 -0300
715Subject: [PATCH 2/4] basic sqlite3
716
717---
718 game.cpp | 11 +++++++++++
719 map.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++
720 vehicle.cpp | 4 ++--
721 vehicle.h | 4 ++--
722 4 files changed, 62 insertions(+), 4 deletions(-)
723
724diff --git a/game.cpp b/game.cpp
725index 2cd6a86..6e0c17f 100644
726--- a/game.cpp
727+++ b/game.cpp
728@@ -14,6 +14,8 @@
729 #include <dirent.h>
730 #include <sys/stat.h>
731
732+#include "savedb.h"
733+
734 #define MAX_MONSTERS_MOVING 40 // Efficiency!
735
736 void intro();
737@@ -90,6 +92,7 @@ game::game()
738 for (int j = 0; j < SEEX * MAPSIZE; j++)
739 grscent[i][j] = 0;
740 }
741+
742 if (opening_screen()) {// Opening menu
743 // Finally, draw the screen!
744 refresh_all();
745@@ -104,6 +107,9 @@ game::~game()
746 delete itypes[i];
747 for (int i = 0; i < mtypes.size(); i++)
748 delete mtypes[i];
749+
750+ SaveDB::getInstance()->close();
751+
752 delwin(w_terrain);
753 delwin(w_minimap);
754 delwin(w_HP);
755@@ -114,6 +120,7 @@ game::~game()
756
757 bool game::opening_screen()
758 {
759+
760 WINDOW* w_open = newwin(25, 80, 0, 0);
761 erase();
762 for (int i = 0; i < 80; i++)
763@@ -154,6 +161,10 @@ fivedozenwhales@gmail.com.");
764 if (tmp.find(".template") != std::string::npos)
765 templates.push_back(tmp.substr(0, tmp.find(".template")));
766 }
767+
768+ if (!SaveDB::getInstance()->init(this))
769+ return false;
770+
771 int sel1 = 0, sel2 = 1, layer = 1;
772 char ch;
773 bool start = false;
774diff --git a/map.cpp b/map.cpp
775index 6b0b443..6e93092 100644
776--- a/map.cpp
777+++ b/map.cpp
778@@ -7,6 +7,8 @@
779 #include <stdlib.h>
780 #include <fstream>
781
782+#include "savedb.h"
783+
784 #define SGN(a) (((a)<0) ? -1 : 1)
785 #define INBOUNDS(x, y) \
786 (x >= 0 && x < SEEX * my_MAPSIZE && y >= 0 && y < SEEY * my_MAPSIZE)
787@@ -2270,6 +2272,8 @@ void map::saven(overmap *om, unsigned int turn, int worldx, int worldy,
788 int gridx, int gridy)
789 {
790 int n = gridx + gridy * my_MAPSIZE;
791+
792+#ifndef USE_SAVEDB
793 // Open appropriate file.
794 char buff[32];
795 sprintf(buff, "save/m.%d.%d.%d", om->posx * OMAPX * 2 + worldx + gridx,
796@@ -2347,6 +2351,13 @@ void map::saven(overmap *om, unsigned int turn, int worldx, int worldy,
797 fout << "c " << grid[n].comp.save_data() << std::endl;
798 // Close the file; that's all we need.
799 fout.close();
800+#else
801+ SaveDB::getInstance()->saveSubmap(om->posx * OMAPX * 2 + worldx + gridx,
802+ om->posy * OMAPY * 2 + worldy + gridy,
803+ om->posz,
804+ turn,
805+ grid[n]);
806+#endif
807 }
808
809 // worldx & worldy specify where in the world this is;
810@@ -2356,6 +2367,7 @@ void map::saven(overmap *om, unsigned int turn, int worldx, int worldy,
811 // 0,2 1,2 2,2
812 bool map::loadn(game *g, int worldx, int worldy, int gridx, int gridy)
813 {
814+#ifndef USE_SAVEDB
815 char fname[32];
816 char line[SEEX];
817 char ch = 0;
818@@ -2476,6 +2488,41 @@ bool map::loadn(game *g, int worldx, int worldy, int gridx, int gridy)
819 return false;
820 }
821 return true;
822+#else // USE_SAVEDB
823+ int gridn = gridx + gridy * my_MAPSIZE;
824+ int turndif = g->turn;
825+ if (SaveDB::getInstance()->loadSubmap(g,
826+ g->cur_om.posx * OMAPX * 2 + worldx + gridx,
827+ g->cur_om.posy * OMAPY * 2 + worldy + gridy,
828+ g->cur_om.posz,
829+ turndif,
830+ grid[gridn],
831+ gridx,gridy)) {
832+ if (grid[gridn].field_count > 0 && turndif >= 8) {
833+ for (int i = 0; i < int(turndif / 8) && i < 5000; i++) {
834+ if (!process_fields(g))
835+ i = int(turndif / 8) + 1;
836+ }
837+ }
838+
839+ } else {
840+ map tmp_map(itypes, mapitems, traps);
841+ // overx, overy is where in the overmap we need to pull data from
842+ // Each overmap square is two nonants; to prevent overlap, generate only at
843+ // squares divisible by 2.
844+ int newmapx = worldx + gridx - ((worldx + gridx) % 2);
845+ int newmapy = worldy + gridy - ((worldy + gridy) % 2);
846+ if (worldx + gridx < 0)
847+ newmapx = worldx + gridx;
848+ if (worldy + gridy < 0)
849+ newmapy = worldy + gridy;
850+ if (worldx + gridx < 0)
851+ newmapx = worldx + gridx;
852+ tmp_map.generate(g, &(g->cur_om), newmapx, newmapy, int(g->turn));
853+ return false;
854+ }
855+ return true;
856+#endif
857 }
858
859 void map::copy_grid(int to, int from)
860diff --git a/vehicle.cpp b/vehicle.cpp
861index 0d909d1..03e828c 100644
862--- a/vehicle.cpp
863+++ b/vehicle.cpp
864@@ -52,7 +52,7 @@ bool vehicle::player_in_control (player *p)
865 return part_with_feature(veh_part, vpf_controls, false) >= 0 && p->in_vehicle;
866 }
867
868-void vehicle::load (std::ifstream &stin)
869+void vehicle::load (std::istream &stin)
870 {
871 int t;
872 int fdir, mdir, skd, prts, cr_on;
873@@ -117,7 +117,7 @@ void vehicle::load (std::ifstream &stin)
874 precalc_mounts (0, face.dir());
875 }
876
877-void vehicle::save (std::ofstream &stout)
878+void vehicle::save (std::ostream &stout)
879 {
880 stout <<
881 int(type) << " " <<
882diff --git a/vehicle.h b/vehicle.h
883index 34a4972..3b1dacb 100644
884--- a/vehicle.h
885+++ b/vehicle.h
886@@ -117,10 +117,10 @@ public:
887 void init_state();
888
889 // load and init vehicle data from stream. This implies valid save data!
890- void load (std::ifstream &stin);
891+ void load (std::istream &stin);
892
893 // Save vehicle data to stream
894- void save (std::ofstream &stout);
895+ void save (std::ostream &stout);
896
897 // get vpart type info for part number (part at given vector index)
898 const vpart_info& part_info (int index);
899--
9001.7.5.4
901
902
903From f6535cc5f885b47c3e7b7fb2be6b8eb967996fc0 Mon Sep 17 00:00:00 2001
904From: monkey <monkey@monkey.(none)>
905Date: Sun, 19 Aug 2012 03:27:50 -0300
906Subject: [PATCH 3/4] turndif for fields
907
908---
909 savedb.cpp | 2 +-
910 1 files changed, 1 insertions(+), 1 deletions(-)
911
912diff --git a/savedb.cpp b/savedb.cpp
913index d425186..63015d9 100644
914--- a/savedb.cpp
915+++ b/savedb.cpp
916@@ -354,7 +354,7 @@ bool SaveDB::loadSubmap(game* g, int x,int y,int z,int &turn,
917 smap.vehicles.push_back(veh);
918 }
919
920- turn = old_turn;
921+ turn = turndif;
922 return true;
923 }
924
925--
9261.7.5.4
927
928
929From b4de7d84a47675f8a915e5a2d121ccd4dd18d646 Mon Sep 17 00:00:00 2001
930From: monkey <monkey@monkey.(none)>
931Date: Sun, 19 Aug 2012 18:57:21 -0300
932Subject: [PATCH 4/4] spawns points bugs
933
934---
935 savedb.cpp | 16 ++++++++--------
936 1 files changed, 8 insertions(+), 8 deletions(-)
937
938diff --git a/savedb.cpp b/savedb.cpp
939index 63015d9..d9c7b76 100644
940--- a/savedb.cpp
941+++ b/savedb.cpp
942@@ -457,7 +457,7 @@ void SaveDB::saveSubmap(int x,int y,int z,int turn,const submap& smap)
943 fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
944 exit(rc);
945 }
946- // store
947+ // store spawns
948 for (std::vector<spawn_point>::const_iterator sIt = smap.spawns.begin(); sIt != smap.spawns.end();++sIt) {
949 const spawn_point& s = *sIt;
950 sqlite3_clear_bindings(saveSpawn_stmt);
951@@ -467,12 +467,12 @@ void SaveDB::saveSubmap(int x,int y,int z,int turn,const submap& smap)
952 sqlite3_bind_int(saveSpawn_stmt, 3, z);
953 sqlite3_bind_text(saveSpawn_stmt, 4, s.name.c_str(), s.name.size(), SQLITE_TRANSIENT);
954 sqlite3_bind_int(saveSpawn_stmt, 5, s.type );
955- sqlite3_bind_int(saveItem_stmt, 6, s.count);
956- sqlite3_bind_int(saveItem_stmt, 7, s.posx);
957- sqlite3_bind_int(saveItem_stmt, 8, s.posy);
958- sqlite3_bind_int(saveItem_stmt, 9, s.faction_id);
959- sqlite3_bind_int(saveItem_stmt, 10, s.mission_id);
960- sqlite3_bind_int(saveItem_stmt, 11, s.friendly);
961+ sqlite3_bind_int(saveSpawn_stmt, 6, s.count);
962+ sqlite3_bind_int(saveSpawn_stmt, 7, s.posx);
963+ sqlite3_bind_int(saveSpawn_stmt, 8, s.posy);
964+ sqlite3_bind_int(saveSpawn_stmt, 9, s.faction_id);
965+ sqlite3_bind_int(saveSpawn_stmt, 10, s.mission_id);
966+ sqlite3_bind_int(saveSpawn_stmt, 11, s.friendly);
967 while ((rc = sqlite3_step(saveSpawn_stmt)) == SQLITE_BUSY) ; // other processes can block this
968 if (rc != SQLITE_DONE) {
969 fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
970@@ -491,7 +491,7 @@ void SaveDB::saveSubmap(int x,int y,int z,int turn,const submap& smap)
971 fprintf(stderr, "Error saving submap: %s\n", sqlite3_errmsg(db));
972 exit(rc);
973 }
974- // store
975+ // store vehicles
976 for (std::vector<vehicle>::const_iterator vIt = smap.vehicles.begin();vIt != smap.vehicles.end();++vIt) {
977 std::ostringstream oss;
978 vehicle v = *vIt;
979--
9801.7.5.4