From 00b138101781dbd16d17262e66c46f2973674160 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 29 Sep 2021 19:20:40 +0200 Subject: [PATCH] Generate spawn hut --- src/map.c | 2 +- src/server/database.c | 94 ++++++++++----------- src/server/database.h | 2 + src/server/server.c | 1 + src/server/server_commands.c | 2 +- src/server/server_map.c | 154 +++++++++++++++++++++++++++++++++-- src/server/server_map.h | 5 +- 7 files changed, 202 insertions(+), 58 deletions(-) diff --git a/src/map.c b/src/map.c index db56bca..5da5acd 100644 --- 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); } diff --git a/src/server/database.c b/src/server/database.c index 9409c93..9c8bd23 100644 --- a/src/server/database.c +++ b/src/server/database.c @@ -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) { diff --git a/src/server/database.h b/src/server/database.h index 608eae7..d063e1b 100644 --- a/src/server/database.h +++ b/src/server/database.h @@ -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 diff --git a/src/server/server.c b/src/server/server.c index 90f67f9..3f9a584 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -78,6 +78,7 @@ static void server_run(int fd) database_init(); server_map_init(&server); + server_map_prepare_spawn(); while (! interrupted) accept_client(); diff --git a/src/server/server_commands.c b/src/server/server_commands.c index 1eb93be..1d48fa0 100644 --- a/src/server/server_commands.c +++ b/src/server/server_commands.c @@ -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); } diff --git a/src/server/server_map.c b/src/server/server_map.c index bf2d262..83b81f7 100644 --- a/src/server/server_map.c +++ b/src/server/server_map.c @@ -2,10 +2,11 @@ #include #include #include +#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); + } +} diff --git a/src/server/server_map.h b/src/server/server_map.h index d7a1905..d4049fb 100644 --- a/src/server/server_map.h +++ b/src/server/server_map.h @@ -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 -- 2.44.0