]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/map.c
5da5acd8d58b8a1e3d535cd4aa7b8ca6faebcb61
[dragonblocks_alpha.git] / src / map.c
1 #include <stdlib.h>
2 #include <stdbool.h>
3 #include <unistd.h>
4 #include <math.h>
5 #include <endian.h/endian.h>
6 #include <string.h>
7 #include "map.h"
8 #include "util.h"
9
10 Map *map_create(MapCallbacks callbacks)
11 {
12         Map *map = malloc(sizeof(Map));
13         pthread_rwlock_init(&map->rwlck, NULL);
14         pthread_rwlock_init(&map->cached_rwlck, NULL);
15         map->sectors = bintree_create(sizeof(v2s32), NULL);
16         map->cached = NULL;
17         map->callbacks = callbacks;
18         return map;
19 }
20
21 static void free_block(BintreeNode *node, void *arg)
22 {
23         Map *map = arg;
24
25         if (map->callbacks.delete_block)
26                 map->callbacks.delete_block(node->value);
27
28         map_free_block(node->value);
29 }
30
31 static void free_sector(BintreeNode *node, void *arg)
32 {
33         MapSector *sector = node->value;
34
35         bintree_clear(&sector->blocks, &free_block, arg);
36         pthread_rwlock_destroy(&sector->rwlck);
37         free(sector);
38 }
39
40 void map_delete(Map *map)
41 {
42         pthread_rwlock_destroy(&map->rwlck);
43         pthread_rwlock_destroy(&map->cached_rwlck);
44         bintree_clear(&map->sectors, &free_sector, map);
45         free(map);
46 }
47
48 MapSector *map_get_sector(Map *map, v2s32 pos, bool create)
49 {
50         if (create)
51                 pthread_rwlock_wrlock(&map->rwlck);
52         else
53                 pthread_rwlock_rdlock(&map->rwlck);
54
55         BintreeNode **nodeptr = bintree_search(&map->sectors, &pos);
56
57         MapSector *sector = NULL;
58
59         if (*nodeptr) {
60                 sector = (*nodeptr)->value;
61         } else if (create) {
62                 sector = malloc(sizeof(MapSector));
63                 pthread_rwlock_init(&sector->rwlck, NULL);
64                 sector->pos = pos;
65                 sector->blocks = bintree_create(sizeof(s32), NULL);
66
67                 bintree_add_node(&map->sectors, nodeptr, &pos, sector);
68         }
69
70         pthread_rwlock_unlock(&map->rwlck);
71
72         return sector;
73 }
74
75 MapBlock *map_get_block(Map *map, v3s32 pos, bool create)
76 {
77         MapBlock *cached = NULL;
78
79         pthread_rwlock_rdlock(&map->cached_rwlck);
80         cached = map->cached;
81         pthread_rwlock_unlock(&map->cached_rwlck);
82
83         if (cached && v3s32_equals(cached->pos, pos))
84                 return cached;
85
86         MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, create);
87         if (! sector)
88                 return NULL;
89
90         if (create)
91                 pthread_rwlock_wrlock(&sector->rwlck);
92         else
93                 pthread_rwlock_rdlock(&sector->rwlck);
94
95         BintreeNode **nodeptr = bintree_search(&sector->blocks, &pos.y);
96
97         MapBlock *block = NULL;
98
99         if (*nodeptr) {
100                 block = (*nodeptr)->value;
101
102                 pthread_mutex_lock(&block->mtx);
103                 if (map->callbacks.get_block && ! map->callbacks.get_block(block, create)) {
104                         pthread_mutex_unlock(&block->mtx);
105                         block = NULL;
106                 } else {
107                         pthread_mutex_unlock(&block->mtx);
108                         pthread_rwlock_wrlock(&map->cached_rwlck);
109                         map->cached = block;
110                         pthread_rwlock_unlock(&map->cached_rwlck);
111                 }
112         } else if (create) {
113                 bintree_add_node(&sector->blocks, nodeptr, &pos.y, block = map_allocate_block(pos));
114
115                 if (map->callbacks.create_block)
116                         map->callbacks.create_block(block);
117         }
118
119         pthread_rwlock_unlock(&sector->rwlck);
120
121         return block;
122 }
123
124 MapBlock *map_allocate_block(v3s32 pos)
125 {
126         MapBlock *block = malloc(sizeof(MapBlock));
127         block->pos = pos;
128         block->extra = NULL;
129         pthread_mutexattr_t attr;
130         pthread_mutexattr_init(&attr);
131         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
132         pthread_mutex_init(&block->mtx, &attr);
133         return block;
134 }
135
136 void map_free_block(MapBlock *block)
137 {
138         pthread_mutex_destroy(&block->mtx);
139         free(block);
140 }
141
142 bool map_deserialize_node(int fd, MapNode *node)
143 {
144         Node type;
145
146         if (! read_u32(fd, &type))
147                 return false;
148
149         if (type >= NODE_UNLOADED)
150                 type = NODE_UNKNOWN;
151
152         *node = map_node_create(type);
153
154         return true;
155 }
156
157 void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr)
158 {
159         MapBlockData uncompressed;
160         ITERATE_MAPBLOCK {
161                 MapNode node = block->data[x][y][z];
162
163                 if (node_definitions[node.type].serialize)
164                         node_definitions[node.type].serialize(&node);
165
166                 node.type = htobe32(node.type);
167                 uncompressed[x][y][z] = node;
168         }
169
170         my_compress(&uncompressed, sizeof(MapBlockData), dataptr, sizeptr);
171 }
172
173 bool map_deserialize_block(MapBlock *block, const char *data, size_t size)
174 {
175         MapBlockData decompressed;
176
177         if (! my_decompress(data, size, &decompressed, sizeof(MapBlockData)))
178                 return false;
179
180         ITERATE_MAPBLOCK {
181                 MapNode node = decompressed[x][y][z];
182                 node.type = be32toh(node.type);
183
184                 if (node.type >= NODE_UNLOADED)
185                         node.type = NODE_UNKNOWN;
186
187                 if (node_definitions[node.type].deserialize)
188                         node_definitions[node.type].deserialize(&node);
189
190                 block->data[x][y][z] = node;
191         }
192
193         return true;
194 }
195
196 v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset)
197 {
198         if (offset)
199                 *offset = (v3u8) {(u32) pos.x % MAPBLOCK_SIZE, (u32) pos.y % MAPBLOCK_SIZE, (u32) pos.z % MAPBLOCK_SIZE};
200         return (v3s32) {floor((double) pos.x / (double) MAPBLOCK_SIZE), floor((double) pos.y / (double) MAPBLOCK_SIZE), floor((double) pos.z / (double) MAPBLOCK_SIZE)};
201 }
202
203 MapNode map_get_node(Map *map, v3s32 pos)
204 {
205         v3u8 offset;
206         v3s32 blockpos = map_node_to_block_pos(pos, &offset);
207         MapBlock *block = map_get_block(map, blockpos, false);
208         if (! block)
209                 return map_node_create(NODE_UNLOADED);
210         return block->data[offset.x][offset.y][offset.z];
211 }
212
213 void map_set_node(Map *map, v3s32 pos, MapNode node, bool create, void *arg)
214 {
215         v3u8 offset;
216         MapBlock *block = map_get_block(map, map_node_to_block_pos(pos, &offset), create);
217         if (block) {
218                 pthread_mutex_lock(&block->mtx);
219                 if (! map->callbacks.set_node || map->callbacks.set_node(block, offset, &node, arg)) {
220                         block->data[offset.x][offset.y][offset.z] = node;
221                         if (map->callbacks.after_set_node)
222                                 map->callbacks.after_set_node(block, offset, arg);
223                 }
224                 pthread_mutex_unlock(&block->mtx);
225         }
226 }
227
228 MapNode map_node_create(Node type)
229 {
230         MapNode node;
231         node.type = type;
232
233         if (node.type != NODE_UNLOADED && node_definitions[node.type].create)
234                 node_definitions[node.type].create(&node);
235
236         return node;
237 }