13 pthread_rwlock_t lock;
16 static TerrainChunk *allocate_chunk(v3s32 pos)
18 TerrainChunk *chunk = malloc(sizeof * chunk);
22 pthread_rwlock_init(&chunk->lock, NULL);
25 chunk->data[x][y][z] = (TerrainNode) {NODE_UNKNOWN, NULL};
30 static void free_chunk(Terrain *terrain, TerrainChunk *chunk)
32 if (terrain->callbacks.delete_node) CHUNK_ITERATE
33 terrain->callbacks.delete_node(&chunk->data[x][y][z]);
35 pthread_rwlock_destroy(&chunk->lock);
39 static void delete_chunk(TerrainChunk *chunk, Terrain *terrain)
41 if (terrain->callbacks.delete_chunk)
42 terrain->callbacks.delete_chunk(chunk);
44 free_chunk(terrain, chunk);
47 static void delete_sector(TerrainSector *sector, Terrain *terrain)
49 tree_clr(§or->chunks, &delete_chunk, terrain, NULL, 0);
50 pthread_rwlock_destroy(§or->lock);
54 static TerrainSector *get_sector(Terrain *terrain, v2s32 pos, int mode)
56 if (mode == CHUNK_MODE_CREATE)
57 pthread_rwlock_wrlock(&terrain->lock);
59 pthread_rwlock_rdlock(&terrain->lock);
61 TreeNode **loc = tree_nfd(&terrain->sectors, &pos, &v2s32_cmp);
62 TerrainSector *sector = NULL;
66 } else if (mode == CHUNK_MODE_CREATE) {
67 sector = malloc(sizeof *sector);
69 tree_ini(§or->chunks);
70 pthread_rwlock_init(§or->lock, NULL);
72 tree_nmk(&terrain->sectors, loc, sector);
75 pthread_rwlock_unlock(&terrain->lock);
80 Terrain *terrain_create()
82 Terrain *terrain = malloc(sizeof *terrain);
83 tree_ini(&terrain->sectors);
84 pthread_rwlock_init(&terrain->lock, NULL);
85 terrain->cache = NULL;
86 pthread_rwlock_init(&terrain->cache_lock, NULL);
90 void terrain_delete(Terrain *terrain)
92 tree_clr(&terrain->sectors, &delete_sector, terrain, NULL, 0);
93 pthread_rwlock_destroy(&terrain->lock);
94 pthread_rwlock_destroy(&terrain->cache_lock);
98 TerrainChunk *terrain_get_chunk(Terrain *terrain, v3s32 pos, int mode)
100 TerrainChunk *cache = NULL;
102 pthread_rwlock_rdlock(&terrain->cache_lock);
103 cache = terrain->cache;
104 pthread_rwlock_unlock(&terrain->cache_lock);
106 if (cache && v3s32_equals(cache->pos, pos))
109 TerrainSector *sector = get_sector(terrain, (v2s32) {pos.x, pos.z}, mode);
113 if (mode == CHUNK_MODE_CREATE)
114 pthread_rwlock_wrlock(§or->lock);
116 pthread_rwlock_rdlock(§or->lock);
118 TreeNode **loc = tree_nfd(§or->chunks, &pos.y, &s32_cmp);
119 TerrainChunk *chunk = NULL;
124 if (terrain->callbacks.get_chunk && !terrain->callbacks.get_chunk(chunk, mode)) {
127 pthread_rwlock_wrlock(&terrain->cache_lock);
128 terrain->cache = chunk;
129 pthread_rwlock_unlock(&terrain->cache_lock);
131 } else if (mode == CHUNK_MODE_CREATE) {
132 tree_nmk(§or->chunks, loc, chunk = allocate_chunk(pos));
134 if (terrain->callbacks.create_chunk)
135 terrain->callbacks.create_chunk(chunk);
138 pthread_rwlock_unlock(§or->lock);
143 TerrainChunk *terrain_get_chunk_nodep(Terrain *terrain, v3s32 nodep, v3s32 *offset, int mode)
145 TerrainChunk *chunk = terrain_get_chunk(terrain, terrain_chunkp(nodep), mode);
148 *offset = terrain_offset(nodep);
152 Blob terrain_serialize_chunk(__attribute__((unused)) Terrain *terrain, TerrainChunk *chunk, void (*callback)(TerrainNode *node, Blob *buffer))
157 if (chunk->data[x][y][z].type != NODE_AIR) {
164 return (Blob) {0, NULL};
166 SerializedTerrainChunk serialized_chunk;
169 TerrainNode *node = &chunk->data[x][y][z];
170 SerializedTerrainNode *serialized = &serialized_chunk.raw.nodes[x][y][z];
172 serialized->type = node->type;
173 serialized->data = (Blob) {0, NULL};
176 callback(node, &serialized->data);
179 Blob buffer = {0, NULL};
180 SerializedTerrainChunk_write(&buffer, &serialized_chunk);
181 SerializedTerrainChunk_free(&serialized_chunk);
185 bool terrain_deserialize_chunk(Terrain *terrain, TerrainChunk *chunk, Blob buffer, void (*callback)(TerrainNode *node, Blob buffer))
187 if (buffer.siz == 0) {
189 if (terrain->callbacks.delete_node)
190 terrain->callbacks.delete_node(&chunk->data[x][y][z]);
192 chunk->data[x][y][z] = (TerrainNode) {NODE_AIR, NULL};
198 // it's important to copy Blobs that have been malloc'd before reading from them
199 // because reading from a Blob modifies its data and size pointer,
200 // but does not free anything
201 SerializedTerrainChunk serialized_chunk = {0};
202 bool success = SerializedTerrainChunk_read(&buffer, &serialized_chunk);
204 if (success) CHUNK_ITERATE {
205 if (terrain->callbacks.delete_node)
206 terrain->callbacks.delete_node(&chunk->data[x][y][z]);
208 TerrainNode *node = &chunk->data[x][y][z];
209 SerializedTerrainNode *serialized = &serialized_chunk.raw.nodes[x][y][z];
211 node->type = serialized->type;
214 callback(node, serialized->data);
217 SerializedTerrainChunk_free(&serialized_chunk);
221 TerrainNode terrain_get_node(Terrain *terrain, v3s32 pos)
224 TerrainChunk *chunk = terrain_get_chunk_nodep(terrain, pos, &offset, CHUNK_MODE_PASSIVE);
226 return (TerrainNode) {COUNT_NODE, NULL};
228 assert(pthread_rwlock_rdlock(&chunk->lock) == 0);
229 TerrainNode node = chunk->data[offset.x][offset.y][offset.z];
230 pthread_rwlock_unlock(&chunk->lock);
235 v3s32 terrain_chunkp(v3s32 pos)
238 floor((double) pos.x / (double) CHUNK_SIZE),
239 floor((double) pos.y / (double) CHUNK_SIZE),
240 floor((double) pos.z / (double) CHUNK_SIZE)};
243 v3s32 terrain_offset(v3s32 pos)
246 (u32) pos.x % CHUNK_SIZE,
247 (u32) pos.y % CHUNK_SIZE,
248 (u32) pos.z % CHUNK_SIZE};