8 static void delete_chunk(TerrainChunk *chunk, Terrain *terrain)
10 if (terrain->callbacks.delete_chunk)
11 terrain->callbacks.delete_chunk(chunk);
13 terrain_free_chunk(chunk);
16 static void delete_sector(TerrainSector *sector, Terrain *terrain)
18 tree_clr(§or->chunks, &delete_chunk, terrain, NULL, 0);
19 pthread_rwlock_destroy(§or->lock);
23 Terrain *terrain_create()
25 Terrain *terrain = malloc(sizeof *terrain);
26 tree_ini(&terrain->sectors);
27 pthread_rwlock_init(&terrain->lock, NULL);
28 terrain->cache = NULL;
29 pthread_rwlock_init(&terrain->cache_lock, NULL);
33 void terrain_delete(Terrain *terrain)
35 tree_clr(&terrain->sectors, &delete_sector, terrain, NULL, 0);
36 pthread_rwlock_destroy(&terrain->lock);
37 pthread_rwlock_destroy(&terrain->cache_lock);
41 TerrainSector *terrain_get_sector(Terrain *terrain, v2s32 pos, bool create)
44 pthread_rwlock_wrlock(&terrain->lock);
46 pthread_rwlock_rdlock(&terrain->lock);
48 TreeNode **loc = tree_nfd(&terrain->sectors, &pos, &v2s32_cmp);
49 TerrainSector *sector = NULL;
54 sector = malloc(sizeof *sector);
56 tree_ini(§or->chunks);
57 pthread_rwlock_init(§or->lock, NULL);
59 tree_nmk(&terrain->sectors, loc, sector);
62 pthread_rwlock_unlock(&terrain->lock);
67 TerrainChunk *terrain_get_chunk(Terrain *terrain, v3s32 pos, bool create)
69 TerrainChunk *cache = NULL;
71 pthread_rwlock_rdlock(&terrain->cache_lock);
72 cache = terrain->cache;
73 pthread_rwlock_unlock(&terrain->cache_lock);
75 if (cache && v3s32_equals(cache->pos, pos))
78 TerrainSector *sector = terrain_get_sector(terrain, (v2s32) {pos.x, pos.z}, create);
83 pthread_rwlock_wrlock(§or->lock);
85 pthread_rwlock_rdlock(§or->lock);
87 TreeNode **loc = tree_nfd(§or->chunks, &pos.y, &s32_cmp);
88 TerrainChunk *chunk = NULL;
93 pthread_mutex_lock(&chunk->mtx);
94 if (terrain->callbacks.get_chunk && !terrain->callbacks.get_chunk(chunk, create)) {
95 pthread_mutex_unlock(&chunk->mtx);
98 pthread_mutex_unlock(&chunk->mtx);
99 pthread_rwlock_wrlock(&terrain->cache_lock);
100 terrain->cache = chunk;
101 pthread_rwlock_unlock(&terrain->cache_lock);
104 tree_nmk(§or->chunks, loc, chunk = terrain_allocate_chunk(pos));
106 if (terrain->callbacks.create_chunk)
107 terrain->callbacks.create_chunk(chunk);
110 pthread_rwlock_unlock(§or->lock);
115 TerrainChunk *terrain_allocate_chunk(v3s32 pos)
117 TerrainChunk *chunk = malloc(sizeof * chunk);
118 chunk->level = pos.y;
121 pthread_mutexattr_t attr;
122 pthread_mutexattr_init(&attr);
123 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
124 pthread_mutex_init(&chunk->mtx, &attr);
127 chunk->data[x][y][z] = terrain_node_create(NODE_UNKNOWN, (Blob) {0, NULL});
132 void terrain_free_chunk(TerrainChunk *chunk)
135 terrain_node_delete(chunk->data[x][y][z]);
137 pthread_mutex_destroy(&chunk->mtx);
141 Blob terrain_serialize_chunk(TerrainChunk *chunk)
146 if (chunk->data[x][y][z].type != NODE_AIR) {
153 return (Blob) {0, NULL};
155 SerializedTerrainChunk chunk_data;
158 TerrainNode *node = &chunk->data[x][y][z];
159 SerializedTerrainNode *node_data = &chunk_data.raw.nodes[x][y][z];
161 *node_data = (SerializedTerrainNode) {
169 NodeDef *def = &node_defs[node->type];
172 def->serialize(&node_data->data, node->data);
175 Blob buffer = {0, NULL};
176 SerializedTerrainChunk_write(&buffer, &chunk_data);
177 SerializedTerrainChunk_free(&chunk_data);
182 bool terrain_deserialize_chunk(TerrainChunk *chunk, Blob buffer)
184 if (buffer.siz == 0) {
186 chunk->data[x][y][z] = terrain_node_create(NODE_AIR, (Blob) {0, NULL});
191 // it's important to copy Blobs that have been malloc'd before reading from them
192 // because reading from a Blob modifies its data and size pointer,
193 // but does not free anything
194 SerializedTerrainChunk chunk_data = {0};
195 bool success = SerializedTerrainChunk_read(&buffer, &chunk_data);
197 if (success) CHUNK_ITERATE
198 chunk->data[x][y][z] = terrain_node_create(chunk_data.raw.nodes[x][y][z].type, chunk_data.raw.nodes[x][y][z].data);
200 SerializedTerrainChunk_free(&chunk_data);
204 v3s32 terrain_node_to_chunk_pos(v3s32 pos, v3u8 *offset)
207 *offset = (v3u8) {(u32) pos.x % CHUNK_SIZE, (u32) pos.y % CHUNK_SIZE, (u32) pos.z % CHUNK_SIZE};
208 return (v3s32) {floor((double) pos.x / (double) CHUNK_SIZE), floor((double) pos.y / (double) CHUNK_SIZE), floor((double) pos.z / (double) CHUNK_SIZE)};
211 TerrainNode terrain_get_node(Terrain *terrain, v3s32 pos)
214 v3s32 chunkpos = terrain_node_to_chunk_pos(pos, &offset);
215 TerrainChunk *chunk = terrain_get_chunk(terrain, chunkpos, false);
217 return terrain_node_create(NODE_UNLOADED, (Blob) {0, NULL});
218 return chunk->data[offset.x][offset.y][offset.z];
221 void terrain_set_node(Terrain *terrain, v3s32 pos, TerrainNode node, bool create, void *arg)
224 TerrainChunk *chunk = terrain_get_chunk(terrain, terrain_node_to_chunk_pos(pos, &offset), create);
229 pthread_mutex_lock(&chunk->mtx);
230 if (!terrain->callbacks.set_node || terrain->callbacks.set_node(chunk, offset, &node, arg)) {
231 chunk->data[offset.x][offset.y][offset.z] = node;
232 if (terrain->callbacks.after_set_node)
233 terrain->callbacks.after_set_node(chunk, offset, arg);
235 terrain_node_delete(node);
237 pthread_mutex_unlock(&chunk->mtx);
240 TerrainNode terrain_node_create(NodeType type, Blob buffer)
242 if (type >= NODE_UNLOADED)
245 NodeDef *def = &node_defs[type];
249 node.data = def->data_size ? malloc(def->data_size) : NULL;
254 if (def->deserialize)
255 def->deserialize(&buffer, node.data);
260 void terrain_node_delete(TerrainNode node)
262 NodeDef *def = &node_defs[node.type];