]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/server/database.c
Portable endian.h header
[dragonblocks_alpha.git] / src / server / database.c
1 #include <stdio.h>
2 #include <endian.h/endian.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sqlite3.h>
6 #include "server/database.h"
7 #include "server/server_map.h"
8 #include "util.h"
9
10 static sqlite3 *database;
11
12 // utility functions
13
14 // print SQLite3 error message for failed block SQL statement
15 static void print_block_error(MapBlock *block, const char *action)
16 {
17         printf("Database error with %s block at (%d, %d, %d): %s\n", action, block->pos.x, block->pos.y, block->pos.z, sqlite3_errmsg(database));
18 }
19
20 // prepare a SQLite3 block statement and bind the position
21 static sqlite3_stmt *prepare_block_statement(MapBlock *block, const char *action, const char *sql)
22 {
23         sqlite3_stmt *stmt;
24
25         if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) != SQLITE_OK) {
26                 print_block_error(block, action);
27                 return NULL;
28         }
29
30         size_t psize = sizeof(s32) * 3;
31         s32 *pos = malloc(psize);
32         pos[0] = htobe32(block->pos.x);
33         pos[1] = htobe32(block->pos.y);
34         pos[2] = htobe32(block->pos.z);
35
36         sqlite3_bind_blob(stmt, 1, pos, psize, &free);
37
38         return stmt;
39 }
40
41 // public functions
42
43 // open and initialize world SQLite3 database
44 void database_init()
45 {
46         char *err;
47
48         if (sqlite3_open_v2("world.sqlite", &database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
49                 printf("Failed to open database: %s\n", sqlite3_errmsg(database));
50         } else if (sqlite3_exec(database, "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INT, size INT, data BLOB, mgsb_size INT, mgsb_data BLOB);", NULL, NULL, &err) != SQLITE_OK) {
51                 printf("Failed to initialize database: %s\n", err);
52                 sqlite3_free(err);
53         }
54 }
55
56 // close database
57 void database_deinit()
58 {
59         sqlite3_close(database);
60 }
61
62 // load a block from map database (initializes state, mgs buffer and data), returns false on failure
63 bool database_load_block(MapBlock *block)
64 {
65         sqlite3_stmt *stmt;
66
67         if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, size, data, mgsb_size, mgsb_data FROM map WHERE pos=?")))
68                 return false;
69
70         int rc = sqlite3_step(stmt);
71         bool found = rc == SQLITE_ROW;
72
73         if (found) {
74                 MapBlockExtraData *extra = block->extra;
75
76                 extra->state = sqlite3_column_int(stmt, 0) ? MBS_READY : MBS_CREATED;
77                 extra->size = sqlite3_column_int64(stmt, 1);
78                 extra->data = malloc(extra->size);
79                 memcpy(extra->data, sqlite3_column_blob(stmt, 2), extra->size);
80
81                 MapgenStageBuffer decompressed_mgsb;
82                 my_decompress(sqlite3_column_blob(stmt, 4), sqlite3_column_int64(stmt, 3), &decompressed_mgsb, sizeof(MapgenStageBuffer));
83
84                 ITERATE_MAPBLOCK extra->mgs_buffer[x][y][z] = be32toh(decompressed_mgsb[x][y][z]);
85
86                 if (! map_deserialize_block(block, extra->data, extra->size))
87                         printf("Error with deserializing block at (%d, %d, %d)\n", block->pos.x, block->pos.y, block->pos.z);
88         } else if (rc != SQLITE_DONE) {
89                 print_block_error(block, "loading");
90         }
91
92         sqlite3_finalize(stmt);
93         return found;
94 }
95
96 // save a block to database
97 void database_save_block(MapBlock *block)
98 {
99         sqlite3_stmt *stmt;
100
101         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)")))
102                 return;
103
104         MapBlockExtraData *extra = block->extra;
105
106         MapgenStageBuffer uncompressed_mgsb;
107         ITERATE_MAPBLOCK uncompressed_mgsb[x][y][z] = htobe32(extra->mgs_buffer[x][y][z]);
108
109         char *mgsb_data;
110         size_t mgsb_size;
111
112         my_compress(&uncompressed_mgsb, sizeof(MapgenStageBuffer), &mgsb_data, &mgsb_size);
113
114         sqlite3_bind_int(stmt, 2, extra->state > MBS_CREATED);
115         sqlite3_bind_int64(stmt, 3, extra->size);
116         sqlite3_bind_blob(stmt, 4, extra->data, extra->size, SQLITE_TRANSIENT);
117         sqlite3_bind_int64(stmt, 5, mgsb_size);
118         sqlite3_bind_blob(stmt, 6, mgsb_data, mgsb_size, &free);
119
120         if (sqlite3_step(stmt) != SQLITE_DONE)
121                 print_block_error(block, "saving");
122
123         sqlite3_finalize(stmt);
124 }