X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmap.c;h=ca8d2839f7f0bfab267b71f39e032c3c879f7018;hb=4cd7c094f349ede7284453ba63426adeeb43b179;hp=ce69123f5f7ef2798223fe8d44da9488ec09eb70;hpb=f7deb7df68df562c6eaa97759b172da5080d2471;p=dragonblocks_alpha.git diff --git a/src/map.c b/src/map.c index ce69123..ca8d283 100644 --- a/src/map.c +++ b/src/map.c @@ -1,137 +1,140 @@ #include #include +#include #include +#include +#include #include "map.h" #include "util.h" -#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1 - -static s8 sector_compare(void *hash, void *sector) -{ - s64 d = *((u64 *) hash) - (*(MapSector **) sector)->hash; - return CMPBOUNDS(d); -} - -static s8 block_compare(void *level, void *block) -{ - s32 d = *((s32 *) level) - (*(MapBlock **) block)->pos.y; - return CMPBOUNDS(d); -} - -static MapBlock *allocate_block(v3s32 pos) -{ - MapBlock *block = malloc(sizeof(MapBlock)); - block->pos = pos; - block->extra = NULL; - return block; -} - -static MapBlock **get_block_ptr(MapSector *sector, size_t idx) +Map *map_create() { - return (MapBlock **) sector->blocks.ptr + idx; + Map *map = malloc(sizeof(Map)); + pthread_rwlock_init(&map->rwlck, NULL); + pthread_rwlock_init(&map->cached_rwlck, NULL); + map->sectors = bintree_create(sizeof(v2s32)); + map->cached = NULL; + return map; } -static MapSector **get_sector_ptr(Map *map, size_t idx) +static void free_block(void *block) { - return (MapSector **) map->sectors.ptr + idx; + map_free_block(block); } -Map *map_create() +static void free_sector(void *sector_void) { - Map *map = malloc(sizeof(Map)); - map->sectors = array_create(sizeof(MapSector *)); - map->sectors.cmp = §or_compare; - return map; + MapSector *sector = sector_void; + bintree_clear(§or->blocks, &free_block); + pthread_rwlock_destroy(§or->rwlck); + free(sector); } void map_delete(Map *map) { - for (size_t s = 0; s < map->sectors.siz; s++) { - MapSector *sector = *get_sector_ptr(map, s); - for (size_t b = 0; b < sector->blocks.siz; b++) - map_free_block(*get_block_ptr(sector, b)); - if (sector->blocks.ptr) - free(sector->blocks.ptr); - free(sector); - } - if (map->sectors.ptr) - free(map->sectors.ptr); + pthread_rwlock_destroy(&map->rwlck); + pthread_rwlock_destroy(&map->cached_rwlck); + bintree_clear(&map->sectors, &free_sector); free(map); } MapSector *map_get_sector(Map *map, v2s32 pos, bool create) { - u64 hash = ((u64) pos.x << 32) + (u64) pos.y; - ArraySearchResult res = array_search(&map->sectors, &hash); + if (create) + pthread_rwlock_wrlock(&map->rwlck); + else + pthread_rwlock_rdlock(&map->rwlck); - if (res.success) - return *get_sector_ptr(map, res.index); - if (! create) - return NULL; + BintreeNode **nodeptr = bintree_search(&map->sectors, &pos); - MapSector *sector = malloc(sizeof(MapSector)); - sector->pos = pos; - sector->hash = hash; - sector->blocks = array_create(sizeof(MapBlock *)); - sector->blocks.cmp = &block_compare; + MapSector *sector = NULL; - array_insert(&map->sectors, §or, res.index); + if (*nodeptr) { + sector = (*nodeptr)->value; + } else if (create) { + sector = malloc(sizeof(MapSector)); + pthread_rwlock_init(§or->rwlck, NULL); + sector->pos = pos; + sector->blocks = bintree_create(sizeof(s32)); + + bintree_add_node(&map->sectors, nodeptr, &pos, sector); + } + + pthread_rwlock_unlock(&map->rwlck); return sector; } MapBlock *map_get_block(Map *map, v3s32 pos, bool create) { + MapBlock *cached = NULL; + + pthread_rwlock_rdlock(&map->cached_rwlck); + cached = map->cached; + pthread_rwlock_unlock(&map->cached_rwlck); + + if (cached && cached->pos.x == pos.x && cached->pos.y == pos.y && cached->pos.z == pos.z) + return cached; + MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, create); if (! sector) return NULL; - ArraySearchResult res = array_search(§or->blocks, &pos.y); + if (create) + pthread_rwlock_wrlock(§or->rwlck); + else + pthread_rwlock_rdlock(§or->rwlck); + + BintreeNode **nodeptr = bintree_search(§or->blocks, &pos.y); MapBlock *block = NULL; - if (res.success) { - block = *get_block_ptr(sector, res.index); - } else if (create) { - block = allocate_block(pos); + if (*nodeptr) { + block = (*nodeptr)->value; - if (map->on_block_create) - map->on_block_create(block); + if (block->state < MBS_READY) { + if (! create) + block = NULL; + } else { + pthread_rwlock_wrlock(&map->cached_rwlck); + map->cached = block; + pthread_rwlock_unlock(&map->cached_rwlck); + } + } else if (create) { + block = map_allocate_block(pos); - array_insert(§or->blocks, &block, res.index); - } else { - return NULL; + bintree_add_node(§or->blocks, nodeptr, &pos.y, block); } - return block->ready ? block : NULL; + pthread_rwlock_unlock(§or->rwlck); + + return block; } -void map_add_block(Map *map, MapBlock *block) +MapBlock *map_allocate_block(v3s32 pos) { - MapSector *sector = map_get_sector(map, (v2s32) {block->pos.x, block->pos.z}, true); - ArraySearchResult res = array_search(§or->blocks, &block->pos.y); - if (res.success) { - MapBlock **ptr = get_block_ptr(sector, res.index); - map_free_block(*ptr); - *ptr = block; - } else { - array_insert(§or->blocks, &block, res.index); - } - if (map->on_block_add) - map->on_block_add(block); + MapBlock *block = malloc(sizeof(MapBlock)); + block->pos = pos; + block->state = MBS_CREATED; + block->extra = NULL; + block->free_extra = NULL; + pthread_mutex_init(&block->mtx, NULL); + return block; } -void map_clear_block(MapBlock *block, v3u8 init_state) +void map_clear_meta(MapBlock *block) { - for (u8 x = 0; x <= init_state.x; x++) - for (u8 y = 0; y <= init_state.y; y++) - for (u8 z = 0; z <= init_state.z; z++) - map_node_clear(&block->data[x][y][z]); + pthread_mutex_lock(&block->mtx); + ITERATE_MAPBLOCK list_clear(&block->metadata[x][y][z]); + pthread_mutex_unlock(&block->mtx); } void map_free_block(MapBlock *block) { - map_clear_block(block, (v3u8) {15, 15, 15}); + map_clear_meta(block); + pthread_mutex_destroy(&block->mtx); + if (block->free_extra) + block->free_extra(block->extra); free(block); } @@ -150,56 +153,93 @@ bool map_deserialize_node(int fd, MapNode *node) return true; } -bool map_serialize_block(int fd, MapBlock *block) +void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr) { - if (! write_v3s32(fd, block->pos)) - return false; + size_t uncompressed_size = sizeof(MapBlockData); + char uncompressed_data[uncompressed_size]; + MapBlockData blockdata; ITERATE_MAPBLOCK { - if (! write_u32(fd, block->data[x][y][z].type)) - return false; + MapNode node = block->data[x][y][z]; + node.type = htobe32(node.type); + blockdata[x][y][z] = node; } + memcpy(uncompressed_data, blockdata, sizeof(MapBlockData)); - return true; + char compressed_data[uncompressed_size]; + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + stream.avail_in = stream.avail_out = uncompressed_size; + stream.next_in = (Bytef *) uncompressed_data; + stream.next_out = (Bytef *) compressed_data; + + deflateInit(&stream, Z_BEST_COMPRESSION); + deflate(&stream, Z_FINISH); + deflateEnd(&stream); + + size_t compressed_size = stream.total_out; + + size_t size = sizeof(MapBlockHeader) + sizeof(MapBlockHeader) + compressed_size; + char *data = malloc(size); + *(MapBlockHeader *) data = htobe16(sizeof(MapBlockHeader) + compressed_size); + *(MapBlockHeader *) (data + sizeof(MapBlockHeader)) = htobe16(uncompressed_size); + memcpy(data + sizeof(MapBlockHeader) + sizeof(MapBlockHeader), compressed_data, compressed_size); + + *sizeptr = size; + *dataptr = data; } -MapBlock *map_deserialize_block(int fd) +bool map_deserialize_block(MapBlock *block, const char *data, size_t size) { - v3s32 pos; + if (size < sizeof(MapBlockHeader)) + return false; - if (! read_v3s32(fd, &pos)) - return NULL; + MapBlockHeader uncompressed_size = be16toh(*(MapBlockHeader *) data); + + if (uncompressed_size < sizeof(MapBlockData)) + return false; + + char decompressed_data[uncompressed_size]; - MapBlock *block = allocate_block(pos); + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + stream.avail_in = size - sizeof(MapBlockHeader); + stream.next_in = (Bytef *) (data + sizeof(MapBlockHeader)); + stream.avail_out = uncompressed_size; + stream.next_out = (Bytef *) decompressed_data; + + inflateInit(&stream); + inflate(&stream, Z_NO_FLUSH); + inflateEnd(&stream); + + if (stream.total_out < uncompressed_size) + return false; + + MapBlockData blockdata; + memcpy(blockdata, decompressed_data, sizeof(MapBlockData)); ITERATE_MAPBLOCK { - if (! map_deserialize_node(fd, &block->data[x][y][z])) { - map_clear_block(block, (v3u8) {x, y, z}); - free(block); - return NULL; - } - } + MapNode node = blockdata[x][y][z]; + node.type = be32toh(node.type); - return block; -} + if (node.type >= NODE_UNLOADED) + node.type = NODE_INVALID; -bool map_serialize(int fd, Map *map) -{ - for (size_t s = 0; s < map->sectors.siz; s++) { - MapSector *sector = *get_sector_ptr(map, s); - for (size_t b = 0; b < sector->blocks.siz; b++) - if (! map_serialize_block(fd, *get_block_ptr(sector, b))) - return false; + block->data[x][y][z] = node; + + block->metadata[x][y][z] = list_create(&list_compare_string); } - return true; -} -void map_deserialize(int fd, Map *map) -{ - MapBlock *block; + block->state = MBS_MODIFIED; - while ((block = map_deserialize_block(fd)) != NULL) - map_add_block(map, block); + return true; } v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset) @@ -224,18 +264,15 @@ void map_set_node(Map *map, v3s32 pos, MapNode node) v3u8 offset; MapBlock *block = map_get_block(map, map_node_to_block_pos(pos, &offset), false); if (block) { - MapNode *current_node = &block->data[offset.x][offset.y][offset.z]; - map_node_clear(current_node); - *current_node = node; + pthread_mutex_lock(&block->mtx); + block->state = MBS_MODIFIED; + list_clear(&block->metadata[offset.x][offset.y][offset.z]); + block->data[offset.x][offset.y][offset.z] = node; + pthread_mutex_unlock(&block->mtx); } } MapNode map_node_create(Node type) { - return (MapNode) {type, list_create(&list_compare_string)}; -} - -void map_node_clear(MapNode *node) -{ - list_clear(&node->meta); + return (MapNode) {type}; }