12 pthread_rwlock_t lock;
15 static TerrainChunk *allocate_chunk(v3s32 pos)
17 TerrainChunk *chunk = malloc(sizeof * chunk);
21 pthread_mutexattr_t attr;
22 pthread_mutexattr_init(&attr);
23 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
24 pthread_mutex_init(&chunk->mtx, &attr);
27 chunk->data[x][y][z] = (TerrainNode) {NODE_UNKNOWN, NULL};
32 static void free_chunk(Terrain *terrain, TerrainChunk *chunk)
34 if (terrain->callbacks.delete_node) CHUNK_ITERATE
35 terrain->callbacks.delete_node(&chunk->data[x][y][z]);
37 pthread_mutex_destroy(&chunk->mtx);
41 static void delete_chunk(TerrainChunk *chunk, Terrain *terrain)
43 if (terrain->callbacks.delete_chunk)
44 terrain->callbacks.delete_chunk(chunk);
46 free_chunk(terrain, chunk);
49 static void delete_sector(TerrainSector *sector, Terrain *terrain)
51 tree_clr(§or->chunks, &delete_chunk, terrain, NULL, 0);
52 pthread_rwlock_destroy(§or->lock);
56 static TerrainSector *get_sector(Terrain *terrain, v2s32 pos, bool create)
59 pthread_rwlock_wrlock(&terrain->lock);
61 pthread_rwlock_rdlock(&terrain->lock);
63 TreeNode **loc = tree_nfd(&terrain->sectors, &pos, &v2s32_cmp);
64 TerrainSector *sector = NULL;
69 sector = malloc(sizeof *sector);
71 tree_ini(§or->chunks);
72 pthread_rwlock_init(§or->lock, NULL);
74 tree_nmk(&terrain->sectors, loc, sector);
77 pthread_rwlock_unlock(&terrain->lock);
82 Terrain *terrain_create()
84 Terrain *terrain = malloc(sizeof *terrain);
85 tree_ini(&terrain->sectors);
86 pthread_rwlock_init(&terrain->lock, NULL);
87 terrain->cache = NULL;
88 pthread_rwlock_init(&terrain->cache_lock, NULL);
92 void terrain_delete(Terrain *terrain)
94 tree_clr(&terrain->sectors, &delete_sector, terrain, NULL, 0);
95 pthread_rwlock_destroy(&terrain->lock);
96 pthread_rwlock_destroy(&terrain->cache_lock);
100 TerrainChunk *terrain_get_chunk(Terrain *terrain, v3s32 pos, bool create)
102 TerrainChunk *cache = NULL;
104 pthread_rwlock_rdlock(&terrain->cache_lock);
105 cache = terrain->cache;
106 pthread_rwlock_unlock(&terrain->cache_lock);
108 if (cache && v3s32_equals(cache->pos, pos))
111 TerrainSector *sector = get_sector(terrain, (v2s32) {pos.x, pos.z}, create);
116 pthread_rwlock_wrlock(§or->lock);
118 pthread_rwlock_rdlock(§or->lock);
120 TreeNode **loc = tree_nfd(§or->chunks, &pos.y, &s32_cmp);
121 TerrainChunk *chunk = NULL;
126 if (terrain->callbacks.get_chunk && !terrain->callbacks.get_chunk(chunk, create)) {
129 pthread_rwlock_wrlock(&terrain->cache_lock);
130 terrain->cache = chunk;
131 pthread_rwlock_unlock(&terrain->cache_lock);
134 tree_nmk(§or->chunks, loc, chunk = allocate_chunk(pos));
136 if (terrain->callbacks.create_chunk)
137 terrain->callbacks.create_chunk(chunk);
140 pthread_rwlock_unlock(§or->lock);
145 TerrainChunk *terrain_get_chunk_nodep(Terrain *terrain, v3s32 nodep, v3s32 *offset, bool create)
147 TerrainChunk *chunk = terrain_get_chunk(terrain, terrain_chunkp(nodep), create);
150 *offset = terrain_offset(nodep);
154 Blob terrain_serialize_chunk(__attribute__((unused)) Terrain *terrain, TerrainChunk *chunk, void (*callback)(TerrainNode *node, Blob *buffer))
159 if (chunk->data[x][y][z].type != NODE_AIR) {
166 return (Blob) {0, NULL};
168 SerializedTerrainChunk serialized_chunk;
171 TerrainNode *node = &chunk->data[x][y][z];
172 SerializedTerrainNode *serialized = &serialized_chunk.raw.nodes[x][y][z];
174 serialized->type = node->type;
175 serialized->data = (Blob) {0, NULL};
178 callback(node, &serialized->data);
181 Blob buffer = {0, NULL};
182 SerializedTerrainChunk_write(&buffer, &serialized_chunk);
183 SerializedTerrainChunk_free(&serialized_chunk);
187 bool terrain_deserialize_chunk(Terrain *terrain, TerrainChunk *chunk, Blob buffer, void (*callback)(TerrainNode *node, Blob buffer))
189 if (buffer.siz == 0) {
191 if (terrain->callbacks.delete_node)
192 terrain->callbacks.delete_node(&chunk->data[x][y][z]);
194 chunk->data[x][y][z] = (TerrainNode) {NODE_AIR, NULL};
199 // it's important to copy Blobs that have been malloc'd before reading from them
200 // because reading from a Blob modifies its data and size pointer,
201 // but does not free anything
202 SerializedTerrainChunk serialized_chunk = {0};
203 bool success = SerializedTerrainChunk_read(&buffer, &serialized_chunk);
205 if (success) CHUNK_ITERATE {
206 if (terrain->callbacks.delete_node)
207 terrain->callbacks.delete_node(&chunk->data[x][y][z]);
209 TerrainNode *node = &chunk->data[x][y][z];
210 SerializedTerrainNode *serialized = &serialized_chunk.raw.nodes[x][y][z];
212 node->type = serialized->type;
215 callback(node, serialized->data);
218 SerializedTerrainChunk_free(&serialized_chunk);
222 void terrain_lock_chunk(TerrainChunk *chunk)
224 if (pthread_mutex_lock(&chunk->mtx) == 0)
227 fprintf(stderr, "[error] failed to lock terrain chunk mutex\n");
231 TerrainNode terrain_get_node(Terrain *terrain, v3s32 pos)
234 TerrainChunk *chunk = terrain_get_chunk_nodep(terrain, pos, &offset, false);
236 return (TerrainNode) {COUNT_NODE, NULL};
238 terrain_lock_chunk(chunk);
239 TerrainNode node = chunk->data[offset.x][offset.y][offset.z];
240 pthread_mutex_unlock(&chunk->mtx);
245 v3s32 terrain_chunkp(v3s32 pos)
248 floor((double) pos.x / (double) CHUNK_SIZE),
249 floor((double) pos.y / (double) CHUNK_SIZE),
250 floor((double) pos.z / (double) CHUNK_SIZE)};
253 v3s32 terrain_offset(v3s32 pos)
256 (u32) pos.x % CHUNK_SIZE,
257 (u32) pos.y % CHUNK_SIZE,
258 (u32) pos.z % CHUNK_SIZE};