2 #include <endian.h/endian.h>
8 #include "server/database.h"
9 #include "server/server_map.h"
13 static sqlite3 *database;
17 // prepare a SQLite3 statement
18 static inline sqlite3_stmt *prepare_statement(const char *sql)
21 return sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) == SQLITE_OK ? stmt : NULL;
24 // print SQLite3 error message for failed block SQL statement
25 static inline void print_block_error(MapBlock *block, const char *action)
27 fprintf(stderr, "Database error with %s block at (%d, %d, %d): %s\n", action, block->pos.x, block->pos.y, block->pos.z, sqlite3_errmsg(database));
30 // prepare a SQLite3 block statement and bind the position
31 static sqlite3_stmt *prepare_block_statement(MapBlock *block, const char *action, const char *sql)
35 if (! (stmt = prepare_statement(sql))) {
36 print_block_error(block, action);
40 size_t psize = sizeof(u32) * 3;
41 u32 *pos = malloc(psize);
42 pos[0] = htobe32(block->pos.x);
43 pos[1] = htobe32(block->pos.y);
44 pos[2] = htobe32(block->pos.z);
46 sqlite3_bind_blob(stmt, 1, pos, psize, &free);
51 // bind v3f64 to sqlite3 statement
52 static inline void bind_v3f64(sqlite3_stmt *stmt, int idx, v3f64 pos)
54 size_t psize = sizeof(f64) * 3;
55 f64 *blob = malloc(psize);
59 sqlite3_bind_blob(stmt, idx, blob, psize, &free);
64 // open and initialize world SQLite3 database
69 if (sqlite3_open_v2("world.sqlite", &database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
70 fprintf(stderr, "Failed to open database: %s\n", sqlite3_errmsg(database));
74 const char *init_stmts[3]= {
75 "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INTEGER, size INTEGER, data BLOB, mgsb_size INTEGER, mgsb_data BLOB);",
76 "CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER);",
77 "CREATE TABLE IF NOT EXISTS players (name TEXT PRIMARY KEY, pos BLOB);"
80 for (int i = 0; i < 3; i++) {
81 if (sqlite3_exec(database, init_stmts[i], NULL, NULL, &err) != SQLITE_OK) {
82 fprintf(stderr, "Failed to initialize database: %s\n", err);
90 if (database_load_meta("seed", &saved_seed)) {
95 database_save_meta("seed", seed);
100 if (database_load_meta("time_of_day", &time_of_day))
101 set_time_of_day(time_of_day);
103 set_time_of_day(12 * MINUTES_PER_HOUR);
107 void database_deinit()
109 database_save_meta("time_of_day", (s64) get_time_of_day());
110 sqlite3_close(database);
113 // load a block from map database (initializes state, mgs buffer and data), returns false on failure
114 bool database_load_block(MapBlock *block)
118 if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, size, data, mgsb_size, mgsb_data FROM map WHERE pos=?")))
121 int rc = sqlite3_step(stmt);
122 bool found = rc == SQLITE_ROW;
125 MapBlockExtraData *extra = block->extra;
127 extra->state = sqlite3_column_int(stmt, 0) ? MBS_READY : MBS_CREATED;
128 extra->size = sqlite3_column_int64(stmt, 1);
129 extra->data = malloc(extra->size);
130 memcpy(extra->data, sqlite3_column_blob(stmt, 2), extra->size);
132 MapgenStageBuffer decompressed_mgsb;
133 my_decompress(sqlite3_column_blob(stmt, 4), sqlite3_column_int64(stmt, 3), &decompressed_mgsb, sizeof(MapgenStageBuffer));
135 ITERATE_MAPBLOCK extra->mgs_buffer[x][y][z] = be32toh(decompressed_mgsb[x][y][z]);
137 if (! map_deserialize_block(block, extra->data, extra->size))
138 printf("Error with deserializing block at (%d, %d, %d)\n", block->pos.x, block->pos.y, block->pos.z);
139 } else if (rc != SQLITE_DONE) {
140 print_block_error(block, "loading");
143 sqlite3_finalize(stmt);
147 // save a block to database
148 void database_save_block(MapBlock *block)
152 if (! (stmt = prepare_block_statement(block, "saving", "REPLACE INTO map (pos, generated, size, data, mgsb_size, mgsb_data) VALUES(?1, ?2, ?3, ?4, ?5, ?6)")))
155 MapBlockExtraData *extra = block->extra;
157 MapgenStageBuffer uncompressed_mgsb;
158 ITERATE_MAPBLOCK uncompressed_mgsb[x][y][z] = htobe32(extra->mgs_buffer[x][y][z]);
163 my_compress(&uncompressed_mgsb, sizeof(MapgenStageBuffer), &mgsb_data, &mgsb_size);
165 sqlite3_bind_int(stmt, 2, extra->state > MBS_CREATED);
166 sqlite3_bind_int64(stmt, 3, extra->size);
167 sqlite3_bind_blob(stmt, 4, extra->data, extra->size, SQLITE_TRANSIENT);
168 sqlite3_bind_int64(stmt, 5, mgsb_size);
169 sqlite3_bind_blob(stmt, 6, mgsb_data, mgsb_size, &free);
171 if (sqlite3_step(stmt) != SQLITE_DONE)
172 print_block_error(block, "saving");
174 sqlite3_finalize(stmt);
178 bool database_load_meta(const char *key, s64 *value_ptr)
182 if (! (stmt = prepare_statement("SELECT value FROM meta WHERE key=?"))) {
183 fprintf(stderr, "Database error with loading %s: %s\n", key, sqlite3_errmsg(database));
187 sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_TRANSIENT);
189 int rc = sqlite3_step(stmt);
190 bool found = rc == SQLITE_ROW;
193 *value_ptr = sqlite3_column_int64(stmt, 0);
194 else if (rc != SQLITE_DONE)
195 fprintf(stderr, "Database error with loading %s: %s\n", key, sqlite3_errmsg(database));
197 sqlite3_finalize(stmt);
201 // save / update a meta entry
202 void database_save_meta(const char *key, s64 value)
206 if (! (stmt = prepare_statement("REPLACE INTO meta (key, value) VALUES(?1, ?2)"))) {
207 fprintf(stderr, "Database error with saving %s: %s\n", key, sqlite3_errmsg(database));
211 sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_TRANSIENT);
212 sqlite3_bind_int64(stmt, 2, value);
214 if (sqlite3_step(stmt) != SQLITE_DONE)
215 fprintf(stderr, "Database error with saving %s: %s\n", key, sqlite3_errmsg(database));
217 sqlite3_finalize(stmt);
220 // load player data from database
221 bool database_load_player(char *name, v3f64 *pos_ptr)
225 if (! (stmt = prepare_statement("SELECT pos FROM players WHERE name=?"))) {
226 fprintf(stderr, "Database error with loading player %s: %s\n", name, sqlite3_errmsg(database));
230 sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_TRANSIENT);
232 int rc = sqlite3_step(stmt);
233 bool found = rc == SQLITE_ROW;
236 const f64 *pos = sqlite3_column_blob(stmt, 0);
237 *pos_ptr = (v3f64) {pos[0], pos[1], pos[2]};
238 } else if (rc != SQLITE_DONE) {
239 fprintf(stderr, "Database error with loading player %s: %s\n", name, sqlite3_errmsg(database));
242 sqlite3_finalize(stmt);
246 // insert new player into database
247 void database_create_player(char *name, v3f64 pos)
251 if (! (stmt = prepare_statement("INSERT INTO players (name, pos) VALUES(?1, ?2)"))) {
252 fprintf(stderr, "Database error with creating player %s: %s\n", name, sqlite3_errmsg(database));
256 sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_TRANSIENT);
257 bind_v3f64(stmt, 2, pos);
259 if (sqlite3_step(stmt) != SQLITE_DONE)
260 fprintf(stderr, "Database error with creating player %s: %s\n", name, sqlite3_errmsg(database));
262 sqlite3_finalize(stmt);
265 // update player position
266 void database_update_player_pos(char *name, v3f64 pos)
270 if (! (stmt = prepare_statement("UPDATE players SET pos=?1 WHERE name=?2"))) {
271 fprintf(stderr, "Database error with updating player %s position: %s\n", name, sqlite3_errmsg(database));
275 bind_v3f64(stmt, 1, pos);
276 sqlite3_bind_text(stmt, 2, name, strlen(name), SQLITE_TRANSIENT);
278 if (sqlite3_step(stmt) != SQLITE_DONE)
279 fprintf(stderr, "Database error with updating player %s position: %s\n", name, sqlite3_errmsg(database));
281 sqlite3_finalize(stmt);