5 #include "server/mapdb.h"
6 #include "server/mapgen.h"
7 #include "server/server_map.h"
11 struct ServerMap server_map;
12 static Server *server;
16 // send a block to a client and reset block request
17 static void send_block(Client *client, MapBlock *block)
19 MapBlockExtraData *extra = block->extra;
21 pthread_mutex_lock(&client->mtx);
22 if (client->state == CS_ACTIVE)
23 (void) (write_u32(client->fd, CC_BLOCK) && write_v3s32(client->fd, block->pos) && write_u64(client->fd, extra->size) && write(client->fd, extra->data, extra->size) != -1);
24 pthread_mutex_unlock(&client->mtx);
27 // send block to near clients
28 // block mutex has to be locked
29 static void send_block_to_near(MapBlock *block)
31 MapBlockExtraData *extra = block->extra;
33 if (extra->state == MBS_GENERATING)
36 map_serialize_block(block, &extra->data, &extra->size);
37 mapdb_save_block(server_map.db, block);
39 if (extra->state == MBS_CREATED)
42 pthread_rwlock_rdlock(&server->players_rwlck);
43 ITERATE_LIST(&server->players, pair) {
44 Client *client = pair->value;
46 if (within_simulation_distance(client->pos, block->pos, server->config.simulation_distance))
47 send_block(client, block);
49 pthread_rwlock_unlock(&server->players_rwlck);
52 // list_clear_func callback for sending changed blocks to near clients
53 static void list_send_block(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *arg)
55 MapBlock *block = key;
57 pthread_mutex_lock(&block->mtx);
58 send_block_to_near(block);
59 pthread_mutex_unlock(&block->mtx);
62 // pthread start routine for mapgen thread
63 static void *mapgen_thread(void *arg)
65 MapBlock *block = arg;
66 MapBlockExtraData *extra = block->extra;
68 pthread_mutex_lock(&block->mtx);
69 extra->state = MBS_GENERATING;
70 pthread_mutex_unlock(&block->mtx);
72 List changed_blocks = list_create(NULL);
73 list_put(&changed_blocks, block, NULL);
75 mapgen_generate_block(block, &changed_blocks);
77 pthread_mutex_lock(&block->mtx);
78 extra->state = MBS_READY;
79 pthread_mutex_unlock(&block->mtx);
81 list_clear_func(&changed_blocks, &list_send_block, NULL);
83 if (! server_map.shutting_down) {
84 pthread_mutex_lock(&server_map.mapgen_threads_mtx);
85 list_delete(&server_map.mapgen_threads, &extra->mapgen_thread);
86 pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
92 // launch mapgen thread for block
93 // block mutex has to be locked
94 static void launch_mapgen_thread(MapBlock *block)
96 pthread_mutex_lock(&server_map.mapgen_threads_mtx);
97 pthread_t *thread_ptr = &((MapBlockExtraData *) block->extra)->mapgen_thread;
98 pthread_create(thread_ptr, NULL, mapgen_thread, block);
99 list_put(&server_map.mapgen_threads, thread_ptr, NULL);
100 pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
103 // list_clear_func callback used to join running generator threads on shutdown
104 static void list_join_thread(void *key, __attribute__((unused)) void *value, __attribute__((unused)) void *arg)
106 pthread_join(*(pthread_t *) key, NULL);
110 // note: all these functions require the block mutex to be locked, which is always the case when a map callback is invoked
112 // callback for initializing a newly created block
113 // load block from database or initialize state, mgstage buffer and data
114 static void on_create_block(MapBlock *block)
116 MapBlockExtraData *extra = block->extra = malloc(sizeof(MapBlockExtraData));
118 if (! mapdb_load_block(server_map.db, block)) {
119 extra->state = MBS_CREATED;
123 block->data[x][y][z] = map_node_create(NODE_AIR);
124 block->metadata[x][y][z] = list_create(&list_compare_string);
125 extra->mgs_buffer[x][y][z] = MGS_VOID;
130 // callback for deleting a block
132 static void on_delete_block(MapBlock *block)
134 MapBlockExtraData *extra = block->extra;
142 // callback for determining whether a block should be returned by map_get_block
143 // hold back blocks that are not fully generated except when the create flag is set to true
144 static bool on_get_block(MapBlock *block, bool create)
146 MapBlockExtraData *extra = block->extra;
148 if (extra->state < MBS_READY && ! create)
154 // callback for deciding whether a set_node call succeeds or not
155 // reject set_node calls that try to override nodes placed by later mapgen stages, else update mgs buffer - also make sure block is inserted into changed blocks list
156 static bool on_set_node(MapBlock *block, v3u8 offset, __attribute__((unused)) MapNode *node, void *arg)
158 MapgenSetNodeArg *msn_arg = arg;
167 MapgenStage *old_mgs = &((MapBlockExtraData *) block->extra)->mgs_buffer[offset.x][offset.y][offset.z];
169 if (mgs >= *old_mgs) {
173 list_put(msn_arg->changed_blocks, block, NULL);
181 // callback for when a block changes
182 // send block to near clients if not part of map generation
183 static void on_after_set_node(MapBlock *block, __attribute__((unused)) v3u8 offset, void *arg)
186 send_block_to_near(block);
191 // ServerMap singleton constructor
192 void server_map_init(Server *srv)
196 server_map.map = map_create((MapCallbacks) {
197 .create_block = &on_create_block,
198 .delete_block = &on_delete_block,
199 .get_block = &on_get_block,
200 .set_node = &on_set_node,
201 .after_set_node = &on_after_set_node,
203 server_map.shutting_down = false;
204 server_map.db = mapdb_open("map.sqlite");
205 server_map.mapgen_threads = list_create(NULL);
206 pthread_mutex_init(&server_map.mapgen_threads_mtx, NULL);
209 // ServerMap singleton destructor
210 void server_map_deinit()
212 server_map.shutting_down = true;
214 pthread_mutex_lock(&server_map.mapgen_threads_mtx);
215 list_clear_func(&server_map.mapgen_threads, &list_join_thread, NULL);
216 // pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
217 pthread_mutex_destroy(&server_map.mapgen_threads_mtx);
219 sqlite3_close(server_map.db);
220 map_delete(server_map.map);
223 // handle block request from client (thread safe)
224 void server_map_requested_block(Client *client, v3s32 pos)
226 if (within_simulation_distance(client->pos, pos, server->config.simulation_distance)) {
227 MapBlock *block = map_get_block(server_map.map, pos, true);
229 pthread_mutex_lock(&block->mtx);
230 MapBlockExtraData *extra = block->extra;
232 switch (extra->state) {
234 launch_mapgen_thread(block);
241 send_block(client, block);
243 pthread_mutex_unlock(&block->mtx);