]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Generate spawn hut
authorElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 29 Sep 2021 17:20:40 +0000 (19:20 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 29 Sep 2021 17:20:40 +0000 (19:20 +0200)
src/map.c
src/server/database.c
src/server/database.h
src/server/server.c
src/server/server_commands.c
src/server/server_map.c
src/server/server_map.h

index db56bca0fcfb2e88cb739edc1433f34c4045aed1..5da5acd8d58b8a1e3d535cd4aa7b8ca6faebcb61 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -217,9 +217,9 @@ void map_set_node(Map *map, v3s32 pos, MapNode node, bool create, void *arg)
        if (block) {
                pthread_mutex_lock(&block->mtx);
                if (! map->callbacks.set_node || map->callbacks.set_node(block, offset, &node, arg)) {
+                       block->data[offset.x][offset.y][offset.z] = node;
                        if (map->callbacks.after_set_node)
                                map->callbacks.after_set_node(block, offset, arg);
-                       block->data[offset.x][offset.y][offset.z] = node;
                }
                pthread_mutex_unlock(&block->mtx);
        }
index 9409c93ffcb44a5e6f73b5d01d118a31acdd249c..9c8bd23c72e7f393e404d8579eb1d1afb1db00bd 100644 (file)
@@ -48,49 +48,6 @@ static sqlite3_stmt *prepare_block_statement(MapBlock *block, const char *action
        return stmt;
 }
 
-// load something from meta
-static bool 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 something to meta
-static void 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);
-}
-
 // bind v3f64 to sqlite3 statement
 static inline void bind_v3f64(sqlite3_stmt *stmt, int idx, v3f64 pos)
 {
@@ -130,17 +87,17 @@ void database_init()
 
        s64 saved_seed;
 
-       if (load_meta("seed", &saved_seed)) {
+       if (database_load_meta("seed", &saved_seed)) {
                seed = saved_seed;
        } else {
                srand(time(NULL));
                seed = rand();
-               save_meta("seed", seed);
+               database_save_meta("seed", seed);
        }
 
        s64 time_of_day;
 
-       if (load_meta("time_of_day", &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);
@@ -149,7 +106,7 @@ void database_init()
 // close database
 void database_deinit()
 {
-       save_meta("time_of_day", (s64) get_time_of_day());
+       database_save_meta("time_of_day", (s64) get_time_of_day());
        sqlite3_close(database);
 }
 
@@ -217,6 +174,49 @@ void database_save_block(MapBlock *block)
        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)
 {
index 608eae7859cffe13d884b48afe4be9b42d9a0b41..d063e1b820ecff77231ba06e665b4b935fb24d8e 100644 (file)
@@ -8,6 +8,8 @@ void database_init();                                                                           // open and initialize world SQLite3 database
 void database_deinit();                                                                                // close database
 bool database_load_block(MapBlock *block);                                     // load a block from map database (initializes state, mgs buffer and data), returns false on failure
 void database_save_block(MapBlock *block);                                     // save a block to database
+bool database_load_meta(const char *key, s64 *value_ptr);      // load a meta entry
+void database_save_meta(const char *key, s64 value);           // save / update a meta entry
 bool database_load_player(char *name, v3f64 *pos_ptr);         // load player data from database
 void database_create_player(char *name, v3f64 pos);                    // insert new player into database
 void database_update_player_pos(char *name, v3f64 pos);                // update player position
index 90f67f9769eef6a347329fe1116d91d827518566..3f9a584040204780574e7f407da7ac3ced5da189 100644 (file)
@@ -78,6 +78,7 @@ static void server_run(int fd)
 
        database_init();
        server_map_init(&server);
+       server_map_prepare_spawn();
 
        while (! interrupted)
                accept_client();
index 1eb93be39ec5e7f542a6e225e90295a4f102654a..1d48fa07e5cfae9ff845bf2bbadac1eb2b6067b6 100644 (file)
@@ -38,7 +38,7 @@ static bool auth_handler(Client *client, bool good)
                client->state = CS_ACTIVE;
 
                if (! database_load_player(client->name, &client->pos)) {
-                       client->pos = (v3f64) {0.0, 150.0, 0.0};
+                       client->pos = (v3f64) {0.0, server_map.spawn_height + 0.5, 0.0};
 
                        database_create_player(client->name, client->pos);
                }
index bf2d262cb2ba88aaa0d7ff2fb70174898f0aa553..83b81f7c30966000ee0fda871d0985c1dea96880 100644 (file)
@@ -2,10 +2,11 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
+#include "map.h"
 #include "server/database.h"
 #include "server/mapgen.h"
 #include "server/server_map.h"
-#include "map.h"
+#include "signal_handlers.h"
 #include "util.h"
 
 struct ServerMap server_map;
@@ -33,6 +34,9 @@ static void send_block_to_near(MapBlock *block)
        if (extra->state == MBS_GENERATING)
                return;
 
+       if (extra->data)
+               free(extra->data);
+
        map_serialize_block(block, &extra->data, &extra->size);
        database_save_block(block);
 
@@ -80,11 +84,13 @@ static void *mapgen_thread(void *arg)
 
        list_clear_func(&changed_blocks, &list_send_block, NULL);
 
-       if (! server_map.shutting_down) {
+       pthread_mutex_lock(&server_map.joining_threads_mtx);
+       if (! server_map.joining_threads) {
                pthread_mutex_lock(&server_map.mapgen_threads_mtx);
                list_delete(&server_map.mapgen_threads, &extra->mapgen_thread);
                pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
        }
+       pthread_mutex_unlock(&server_map.joining_threads_mtx);
 
        return NULL;
 }
@@ -185,6 +191,87 @@ static void on_after_set_node(MapBlock *block, unused v3u8 offset, void *arg)
                send_block_to_near(block);
 }
 
+// join all map generation threads
+static void join_mapgen_threads()
+{
+       pthread_mutex_lock(&server_map.joining_threads_mtx);
+       server_map.joining_threads = true;
+       pthread_mutex_unlock(&server_map.joining_threads_mtx);
+
+       pthread_mutex_lock(&server_map.mapgen_threads_mtx);
+       list_clear_func(&server_map.mapgen_threads, &list_join_thread, NULL);
+       pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
+
+       pthread_mutex_lock(&server_map.joining_threads_mtx);
+       server_map.joining_threads = false;
+       pthread_mutex_unlock(&server_map.joining_threads_mtx);
+}
+
+// generate a hut for new players to spawn in
+static void generate_spawn_hut()
+{
+       List changed_blocks = list_create(NULL);
+
+       for (s32 x = -4; x <= +4; x++) {
+               for (s32 y = 0; y <= 3; y++) {
+                       for (s32 z = -3; z <= +2; z++) {
+                               mapgen_set_node((v3s32) {x, server_map.spawn_height + y, z}, (MapNode) {NODE_AIR}, MGS_PLAYER, &changed_blocks);
+                       }
+               }
+       }
+
+       for (s32 x = -5; x <= +5; x++) {
+               for (s32 z = -4; z <= +3; z++) {
+                       mapgen_set_node((v3s32) {x, server_map.spawn_height - 1, z}, (MapNode) {NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+                       mapgen_set_node((v3s32) {x, server_map.spawn_height + 4, z}, (MapNode) {NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+               }
+       }
+
+       for (s32 y = 0; y <= 3; y++) {
+               for (s32 x = -5; x <= +5; x++) {
+                       mapgen_set_node((v3s32) {x, server_map.spawn_height + y, -4}, (MapNode) {((y == 1 || y == 2) && ((x >= -3 && x <= -1) || (x >= +1 && x <= +2))) ? NODE_AIR : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+                       mapgen_set_node((v3s32) {x, server_map.spawn_height + y, +3}, (MapNode) {((y == 1 || y == 2) && ((x >= -3 && x <= -2) || (x >= +1 && x <= +3))) ? NODE_AIR : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+               }
+       }
+
+       for (s32 y = 0; y <= 3; y++) {
+               for (s32 z = -3; z <= +2; z++) {
+                       mapgen_set_node((v3s32) {-5, server_map.spawn_height + y, z}, (MapNode) {NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+                       mapgen_set_node((v3s32) {+5, server_map.spawn_height + y, z}, (MapNode) {((y != 3) && (z == -1 || z == +0)) ? NODE_AIR : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+               }
+       }
+
+       v2s32 posts[6] = {
+               {-4, -3},
+               {-4, +2},
+               {+4, -3},
+               {+4, +2},
+               {+5, -1},
+               {+5, +0},
+       };
+
+       for (int i = 0; i < 6; i++) {
+               for (s32 y = server_map.spawn_height - 2;; y--) {
+                       v3s32 pos = {posts[i].x, y, posts[i].y};
+                       Node node = map_get_node(server_map.map, pos).type;
+
+                       if (i >= 4) {
+                               if (node != NODE_AIR)
+                                       break;
+
+                               pos.y++;
+                       }
+
+                       if (node_definitions[node].solid)
+                               break;
+
+                       mapgen_set_node(pos, (MapNode) {node == NODE_LAVA ? NODE_VULCANO_STONE : NODE_WOOD}, MGS_PLAYER, &changed_blocks);
+               }
+       }
+
+       list_clear_func(&changed_blocks, &list_send_block, NULL);
+}
+
 // public functions
 
 // ServerMap singleton constructor
@@ -199,20 +286,18 @@ void server_map_init(Server *srv)
                .set_node = &on_set_node,
                .after_set_node = &on_after_set_node,
        });
-       server_map.shutting_down = false;
+       server_map.joining_threads = false;
        server_map.mapgen_threads = list_create(NULL);
+       pthread_mutex_init(&server_map.joining_threads_mtx, NULL);
        pthread_mutex_init(&server_map.mapgen_threads_mtx, NULL);
 }
 
 // ServerMap singleton destructor
 void server_map_deinit()
 {
-       server_map.shutting_down = true;
-
-       pthread_mutex_lock(&server_map.mapgen_threads_mtx);
-       list_clear_func(&server_map.mapgen_threads, &list_join_thread, NULL);
+       join_mapgen_threads();
+       pthread_mutex_destroy(&server_map.joining_threads_mtx);
        pthread_mutex_destroy(&server_map.mapgen_threads_mtx);
-
        map_delete(server_map.map);
 }
 
@@ -239,3 +324,56 @@ void server_map_requested_block(Client *client, v3s32 pos)
                pthread_mutex_unlock(&block->mtx);
        }
 }
+
+// prepare spawn region
+void server_map_prepare_spawn()
+{
+       s32 done = 0;
+       s32 dist = server->config.simulation_distance;
+       s32 total = (dist * 2 + 1);
+       total *= total * total;
+       s32 last_percentage = -1;
+
+       for (s32 x = -dist; x <= (s32) dist; x++) {
+               for (s32 y = -dist; y <= (s32) dist; y++) {
+                       for (s32 z = -dist; z <= (s32) dist; z++) {
+                               if (interrupted) {
+                                       join_mapgen_threads();
+                                       return;
+                               }
+
+                               MapBlock *block = map_get_block(server_map.map, (v3s32) {x, y, z}, true);
+
+                               pthread_mutex_lock(&block->mtx);
+                               if (((MapBlockExtraData *) block->extra)->state == MBS_CREATED)
+                                       launch_mapgen_thread(block);
+                               pthread_mutex_unlock(&block->mtx);
+
+                               done++;
+
+                               s32 percentage = 100.0 * done / total;
+
+                               if (percentage > last_percentage) {
+                                       last_percentage = percentage;
+                                       printf("Preparing spawn... %d%%\n", percentage);
+                               }
+                       }
+               }
+       }
+
+       join_mapgen_threads();
+
+       s64 saved_spawn_height;
+       if (database_load_meta("spawn_height", &saved_spawn_height)) {
+               server_map.spawn_height = saved_spawn_height;
+       } else {
+               s32 spawn_height = -1;
+
+               while (map_get_node(server_map.map, (v3s32) {0, ++spawn_height, 0}).type != NODE_AIR);
+                       ;
+
+               server_map.spawn_height = spawn_height + 5;
+               generate_spawn_hut();
+               database_save_meta("spawn_height", server_map.spawn_height);
+       }
+}
index d7a1905de761fe8401ca76aebd8377997a136e2f..d4049fb1ef0f0aeb43cb882ccd5516be96eacb74 100644 (file)
@@ -40,13 +40,16 @@ typedef struct
 
 extern struct ServerMap {
        Map *map;                                                               // map object, data is stored here
-       bool shutting_down;                                             // is a shutdown in progress?
+       bool joining_threads;                                   // prevent threads from removing themselves from the thread list if thread list is being cleared anyway
+       pthread_mutex_t joining_threads_mtx;    // mutex to protect joining threads
        List mapgen_threads;                                    // a list of mapgen threads (need to be joined before shutdown)
        pthread_mutex_t mapgen_threads_mtx;             // mutex to protect mapgen thread list
+       s32 spawn_height;                                               // height to spawn players at
 } server_map; // ServerMap singleton
 
 void server_map_init(Server *server);                                          // ServerMap singleton constructor
 void server_map_deinit();                                                                      // ServerMap singleton destructor
 void server_map_requested_block(Client *client, v3s32 pos);    // handle block request from client (thread safe)
+void server_map_prepare_spawn();                                                       // prepare spawn region
 
 #endif