10 #define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
12 static s8 sector_compare(void *hash, void *sector)
14 s64 d = *((u64 *) hash) - (*(MapSector **) sector)->hash;
18 static s8 block_compare(void *level, void *block)
20 s32 d = *((s32 *) level) - (*(MapBlock **) block)->pos.y;
26 Map *map = malloc(sizeof(Map));
27 pthread_rwlock_init(&map->rwlck, NULL);
28 map->sectors = array_create(sizeof(MapSector *));
29 map->sectors.cmp = §or_compare;
33 void map_delete(Map *map, void (*callback)(void *extra))
35 pthread_rwlock_destroy(&map->rwlck);
36 for (size_t s = 0; s < map->sectors.siz; s++) {
37 MapSector *sector = map_get_sector_raw(map, s);
38 for (size_t b = 0; b < sector->blocks.siz; b++) {
39 MapBlock *block = map_get_block_raw(sector, b);
41 callback(block->extra);
42 map_free_block(block);
44 if (sector->blocks.ptr)
45 free(sector->blocks.ptr);
46 pthread_rwlock_destroy(§or->rwlck);
50 free(map->sectors.ptr);
54 MapSector *map_get_sector_raw(Map *map, size_t idx)
56 return ((MapSector **) map->sectors.ptr)[idx];
59 MapBlock *map_get_block_raw(MapSector *sector, size_t idx)
61 return ((MapBlock **) sector->blocks.ptr)[idx];
64 MapSector *map_get_sector(Map *map, v2s32 pos, bool create)
66 u64 hash = ((u64) pos.x << 32) + (u64) pos.y;
69 pthread_rwlock_wrlock(&map->rwlck);
71 pthread_rwlock_rdlock(&map->rwlck);
73 ArraySearchResult res = array_search(&map->sectors, &hash);
75 MapSector *sector = NULL;
78 sector = map_get_sector_raw(map, res.index);
80 sector = malloc(sizeof(MapSector));
81 pthread_rwlock_init(§or->rwlck, NULL);
84 sector->blocks = array_create(sizeof(MapBlock *));
85 sector->blocks.cmp = &block_compare;
87 array_insert(&map->sectors, §or, res.index);
90 pthread_rwlock_unlock(&map->rwlck);
95 MapBlock *map_get_block(Map *map, v3s32 pos, bool create)
97 MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, create);
102 pthread_rwlock_wrlock(§or->rwlck);
104 pthread_rwlock_rdlock(§or->rwlck);
106 ArraySearchResult res = array_search(§or->blocks, &pos.y);
108 MapBlock *block = NULL;
111 block = map_get_block_raw(sector, res.index);
112 if (block->state < MBS_READY && ! create)
115 block = map_allocate_block(pos);
116 array_insert(§or->blocks, &block, res.index);
119 pthread_rwlock_unlock(§or->rwlck);
124 MapBlock *map_allocate_block(v3s32 pos)
126 MapBlock *block = malloc(sizeof(MapBlock));
128 block->state = MBS_CREATED;
130 pthread_mutex_init(&block->mtx, NULL);
134 void map_clear_meta(MapBlock *block)
136 pthread_mutex_lock(&block->mtx);
137 ITERATE_MAPBLOCK list_clear(&block->metadata[x][y][z]);
138 pthread_mutex_unlock(&block->mtx);
141 void map_free_block(MapBlock *block)
143 map_clear_meta(block);
144 pthread_mutex_destroy(&block->mtx);
148 bool map_deserialize_node(int fd, MapNode *node)
152 if (! read_u32(fd, &type))
155 if (type >= NODE_UNLOADED)
158 *node = map_node_create(type);
163 void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr)
165 size_t uncompressed_size = sizeof(MapBlockData);
166 char uncompressed_data[uncompressed_size];
168 MapBlockData blockdata;
170 MapNode node = block->data[x][y][z];
171 node.type = htobe32(node.type);
172 blockdata[x][y][z] = node;
174 memcpy(uncompressed_data, blockdata, sizeof(MapBlockData));
176 char compressed_data[uncompressed_size];
179 stream.zalloc = Z_NULL;
180 stream.zfree = Z_NULL;
181 stream.opaque = Z_NULL;
183 stream.avail_in = stream.avail_out = uncompressed_size;
184 stream.next_in = (Bytef *) uncompressed_data;
185 stream.next_out = (Bytef *) compressed_data;
187 deflateInit(&stream, Z_BEST_COMPRESSION);
188 deflate(&stream, Z_FINISH);
191 size_t compressed_size = stream.total_out;
193 size_t size = sizeof(MapBlockHeader) + sizeof(MapBlockHeader) + compressed_size;
194 char *data = malloc(size);
195 *(MapBlockHeader *) data = htobe64(sizeof(MapBlockHeader) + compressed_size);
196 *(MapBlockHeader *) (data + sizeof(MapBlockHeader)) = htobe64(uncompressed_size);
197 memcpy(data + sizeof(MapBlockHeader) + sizeof(MapBlockHeader), compressed_data, compressed_size);
203 bool map_deserialize_block(MapBlock *block, const char *data, size_t size)
205 if (size < sizeof(MapBlockHeader))
208 MapBlockHeader uncompressed_size = be64toh(*(MapBlockHeader *) data);
210 if (uncompressed_size < sizeof(MapBlockData))
213 char decompressed_data[uncompressed_size];
216 stream.zalloc = Z_NULL;
217 stream.zfree = Z_NULL;
218 stream.opaque = Z_NULL;
220 stream.avail_in = size - sizeof(u64);
221 stream.next_in = (Bytef *) (data + sizeof(u64));
222 stream.avail_out = uncompressed_size;
223 stream.next_out = (Bytef *) decompressed_data;
225 inflateInit(&stream);
226 inflate(&stream, Z_NO_FLUSH);
229 if (stream.total_out < uncompressed_size)
232 MapBlockData blockdata;
233 memcpy(blockdata, decompressed_data, sizeof(MapBlockData));
236 MapNode node = blockdata[x][y][z];
237 node.type = be32toh(node.type);
239 if (node.type >= NODE_UNLOADED)
240 node.type = NODE_INVALID;
242 block->data[x][y][z] = node;
244 block->metadata[x][y][z] = list_create(&list_compare_string);
247 block->state = MBS_MODIFIED;
252 v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset)
255 *offset = (v3u8) {(u32) pos.x % 16, (u32) pos.y % 16, (u32) pos.z % 16};
256 return (v3s32) {floor((double) pos.x / 16.0), floor((double) pos.y / 16.0), floor((double) pos.z / 16.0)};
259 MapNode map_get_node(Map *map, v3s32 pos)
262 v3s32 blockpos = map_node_to_block_pos(pos, &offset);
263 MapBlock *block = map_get_block(map, blockpos, false);
265 return map_node_create(NODE_UNLOADED);
266 return block->data[offset.x][offset.y][offset.z];
269 void map_set_node(Map *map, v3s32 pos, MapNode node)
272 MapBlock *block = map_get_block(map, map_node_to_block_pos(pos, &offset), false);
274 pthread_mutex_lock(&block->mtx);
275 block->state = MBS_MODIFIED;
276 list_clear(&block->metadata[offset.x][offset.y][offset.z]);
277 block->data[offset.x][offset.y][offset.z] = node;
278 pthread_mutex_unlock(&block->mtx);
282 MapNode map_node_create(Node type)
284 return (MapNode) {type};