+// 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);
+}
+