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