]> git.lizzy.rs Git - dragonblocks_alpha.git/blobdiff - src/server/database.c
Generate spawn hut
[dragonblocks_alpha.git] / src / server / database.c
index 2b5b457da4f9bca68944e01c1eed49578aa9e1e8..9c8bd23c72e7f393e404d8579eb1d1afb1db00bd 100644 (file)
@@ -1,32 +1,44 @@
 #include <stdio.h>
-#include <endian.h>
+#include <endian.h/endian.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
+#include <sqlite3.h>
+#include <time.h>
+#include "day.h"
 #include "server/database.h"
 #include "server/server_map.h"
+#include "perlin.h"
 #include "util.h"
 
+static sqlite3 *database;
+
 // utility functions
 
+// prepare a SQLite3 statement
+static inline sqlite3_stmt *prepare_statement(const char *sql)
+{
+       sqlite3_stmt *stmt;
+       return sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) == SQLITE_OK ? stmt : NULL;
+}
+
 // print SQLite3 error message for failed block SQL statement
-static void print_error(sqlite3 *db, MapBlock *block, const char *action)
+static inline void print_block_error(MapBlock *block, const char *action)
 {
-       printf("Database error with %s block at (%d, %d, %d): %s\n", action, block->pos.x, block->pos.y, block->pos.z, sqlite3_errmsg(db));
+       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));
 }
 
 // prepare a SQLite3 block statement and bind the position
-static sqlite3_stmt *prepare_statement(sqlite3 *db, MapBlock *block, const char *action, const char *sql)
+static sqlite3_stmt *prepare_block_statement(MapBlock *block, const char *action, const char *sql)
 {
        sqlite3_stmt *stmt;
 
-       if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
-               print_error(db, block, action);
+       if (! (stmt = prepare_statement(sql))) {
+               print_block_error(block, action);
                return NULL;
        }
 
-       size_t psize = sizeof(s32) * 3;
-       s32 *pos = malloc(psize);
+       size_t psize = sizeof(u32) * 3;
+       u32 *pos = malloc(psize);
        pos[0] = htobe32(block->pos.x);
        pos[1] = htobe32(block->pos.y);
        pos[2] = htobe32(block->pos.z);
@@ -36,30 +48,74 @@ static sqlite3_stmt *prepare_statement(sqlite3 *db, MapBlock *block, const char
        return stmt;
 }
 
+// bind v3f64 to sqlite3 statement
+static inline void bind_v3f64(sqlite3_stmt *stmt, int idx, v3f64 pos)
+{
+       size_t psize = sizeof(f64) * 3;
+       f64 *blob = malloc(psize);
+       blob[0] = pos.x;
+       blob[1] = pos.y;
+       blob[2] = pos.z;
+       sqlite3_bind_blob(stmt, idx, blob, psize, &free);
+}
+
 // public functions
 
-// open and initialize SQLite3 database at path
-sqlite3 *database_open(const char *path)
+// open and initialize world SQLite3 database
+void database_init()
 {
-       sqlite3 *db;
        char *err;
 
-       if (sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
-               printf("Failed to open database: %s\n", sqlite3_errmsg(db));
-       } else if (sqlite3_exec(db, "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) {
-               printf("Failed to initialize database: %s\n", err);
-               sqlite3_free(err);
+       if (sqlite3_open_v2("world.sqlite", &database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
+               fprintf(stderr, "Failed to open database: %s\n", sqlite3_errmsg(database));
+               return;
+       }
+
+       const char *init_stmts[3]= {
+               "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INTEGER, size INTEGER, data BLOB, mgsb_size INTEGER, mgsb_data BLOB);",
+               "CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER);",
+               "CREATE TABLE IF NOT EXISTS players (name TEXT PRIMARY KEY, pos BLOB);"
+       };
+
+       for (int i = 0; i < 3; i++) {
+               if (sqlite3_exec(database, init_stmts[i], NULL, NULL, &err) != SQLITE_OK) {
+                       fprintf(stderr, "Failed to initialize database: %s\n", err);
+                       sqlite3_free(err);
+                       return;
+               }
+       }
+
+       s64 saved_seed;
+
+       if (database_load_meta("seed", &saved_seed)) {
+               seed = saved_seed;
+       } else {
+               srand(time(NULL));
+               seed = rand();
+               database_save_meta("seed", seed);
        }
 
-       return db;
+       s64 time_of_day;
+
+       if (database_load_meta("time_of_day", &time_of_day))
+               set_time_of_day(time_of_day);
+       else
+               set_time_of_day(12 * MINUTES_PER_HOUR);
+}
+
+// close database
+void database_deinit()
+{
+       database_save_meta("time_of_day", (s64) get_time_of_day());
+       sqlite3_close(database);
 }
 
 // load a block from map database (initializes state, mgs buffer and data), returns false on failure
-bool database_load_block(sqlite3 *db, MapBlock *block)
+bool database_load_block(MapBlock *block)
 {
        sqlite3_stmt *stmt;
 
-       if (! (stmt = prepare_statement(db, block, "loading", "SELECT generated, size, data, mgsb_size, mgsb_data FROM map WHERE pos=?")))
+       if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, size, data, mgsb_size, mgsb_data FROM map WHERE pos=?")))
                return false;
 
        int rc = sqlite3_step(stmt);
@@ -81,7 +137,7 @@ bool database_load_block(sqlite3 *db, MapBlock *block)
                if (! map_deserialize_block(block, extra->data, extra->size))
                        printf("Error with deserializing block at (%d, %d, %d)\n", block->pos.x, block->pos.y, block->pos.z);
        } else if (rc != SQLITE_DONE) {
-               print_error(db, block, "loading");
+               print_block_error(block, "loading");
        }
 
        sqlite3_finalize(stmt);
@@ -89,11 +145,11 @@ bool database_load_block(sqlite3 *db, MapBlock *block)
 }
 
 // save a block to database
-void database_save_block(sqlite3 *db, MapBlock *block)
+void database_save_block(MapBlock *block)
 {
        sqlite3_stmt *stmt;
 
-       if (! (stmt = prepare_statement(db, block, "saving", "REPLACE INTO map (pos, generated, size, data, mgsb_size, mgsb_data) VALUES(?1, ?2, ?3, ?4, ?5, ?6)")))
+       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)")))
                return;
 
        MapBlockExtraData *extra = block->extra;
@@ -113,7 +169,114 @@ void database_save_block(sqlite3 *db, MapBlock *block)
        sqlite3_bind_blob(stmt, 6, mgsb_data, mgsb_size, &free);
 
        if (sqlite3_step(stmt) != SQLITE_DONE)
-               print_error(db, block, "saving");
+               print_block_error(block, "saving");
+
+       sqlite3_finalize(stmt);
+}
+
+// load a meta entry
+bool database_load_meta(const char *key, s64 *value_ptr)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement("SELECT value FROM meta WHERE key=?"))) {
+               fprintf(stderr, "Database error with loading %s: %s\n", key, sqlite3_errmsg(database));
+               return false;
+       }
+
+       sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_TRANSIENT);
+
+       int rc = sqlite3_step(stmt);
+       bool found = rc == SQLITE_ROW;
+
+       if (found)
+               *value_ptr = sqlite3_column_int64(stmt, 0);
+       else if (rc != SQLITE_DONE)
+               fprintf(stderr, "Database error with loading %s: %s\n", key, sqlite3_errmsg(database));
+
+       sqlite3_finalize(stmt);
+       return found;
+}
+
+// save / update a meta entry
+void database_save_meta(const char *key, s64 value)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement("REPLACE INTO meta (key, value) VALUES(?1, ?2)"))) {
+               fprintf(stderr, "Database error with saving %s: %s\n", key, sqlite3_errmsg(database));
+               return;
+       }
+
+       sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_TRANSIENT);
+       sqlite3_bind_int64(stmt, 2, value);
+
+       if (sqlite3_step(stmt) != SQLITE_DONE)
+               fprintf(stderr, "Database error with saving %s: %s\n", key, sqlite3_errmsg(database));
+
+       sqlite3_finalize(stmt);
+}
+
+// load player data from database
+bool database_load_player(char *name, v3f64 *pos_ptr)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement("SELECT pos FROM players WHERE name=?"))) {
+               fprintf(stderr, "Database error with loading player %s: %s\n", name, sqlite3_errmsg(database));
+               return false;
+       }
+
+       sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_TRANSIENT);
+
+       int rc = sqlite3_step(stmt);
+       bool found = rc == SQLITE_ROW;
+
+       if (found) {
+               const f64 *pos = sqlite3_column_blob(stmt, 0);
+               *pos_ptr = (v3f64) {pos[0], pos[1], pos[2]};
+       } else if (rc != SQLITE_DONE) {
+               fprintf(stderr, "Database error with loading player %s: %s\n", name, sqlite3_errmsg(database));
+       }
+
+       sqlite3_finalize(stmt);
+       return found;
+}
+
+// insert new player into database
+void database_create_player(char *name, v3f64 pos)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement("INSERT INTO players (name, pos) VALUES(?1, ?2)"))) {
+               fprintf(stderr, "Database error with creating player %s: %s\n", name, sqlite3_errmsg(database));
+               return;
+       }
+
+       sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_TRANSIENT);
+       bind_v3f64(stmt, 2, pos);
+
+       if (sqlite3_step(stmt) != SQLITE_DONE)
+               fprintf(stderr, "Database error with creating player %s: %s\n", name, sqlite3_errmsg(database));
+
+       sqlite3_finalize(stmt);
+}
+
+// update player position
+void database_update_player_pos(char *name, v3f64 pos)
+{
+       sqlite3_stmt *stmt;
+
+       if (! (stmt = prepare_statement("UPDATE players SET pos=?1 WHERE name=?2"))) {
+               fprintf(stderr, "Database error with updating player %s position: %s\n", name, sqlite3_errmsg(database));
+               return;
+       }
+
+       bind_v3f64(stmt, 1, pos);
+       sqlite3_bind_text(stmt, 2, name, strlen(name), SQLITE_TRANSIENT);
+
+       if (sqlite3_step(stmt) != SQLITE_DONE)
+               fprintf(stderr, "Database error with updating player %s position: %s\n", name, sqlite3_errmsg(database));
 
        sqlite3_finalize(stmt);
 }