]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/server/terrain_gen.c
Fix client terrain crashes and performance
[dragonblocks_alpha.git] / src / server / terrain_gen.c
1 #include <assert.h>
2 #include <math.h>
3 #include <stdlib.h>
4 #include "environment.h"
5 #include "perlin.h"
6 #include "server/biomes.h"
7 #include "server/server_node.h"
8 #include "server/server_terrain.h"
9 #include "server/terrain_gen.h"
10 #include "server/tree.h"
11
12 s32 terrain_gen_get_base_height(v2s32 pos)
13 {
14         return 1.0
15                 * (pnoise2d(U32(pos.x) /  32.0, U32(pos.y) /  32.0, 0.45, 5, seed + OFFSET_HEIGHT)    * 16.0 + 0.0)
16                 * (pnoise2d(U32(pos.x) / 256.0, U32(pos.y) / 256.0, 0.45, 5, seed + OFFSET_HILLYNESS) *  0.5 + 0.5)
17                 + 32.0;
18 }
19
20 // generate a chunk (does not manage chunk state or threading)
21 void terrain_gen_chunk(TerrainChunk *chunk, List *changed_chunks)
22 {
23         TerrainChunkMeta *meta = chunk->extra;
24
25         BiomeArgsChunk chunk_args;
26         BiomeArgsRow row_args;
27         BiomeArgsHeight height_args;
28         BiomeArgsGenerate generate_args;
29         TreeArgsCondition condition_args;
30
31         chunk_args.chunk = condition_args.chunk = chunk;
32         chunk_args.changed_chunks = generate_args.changed_chunks = changed_chunks;
33
34         v3s32 chunkp = {
35                 chunk->pos.x * CHUNK_SIZE,
36                 chunk->pos.y * CHUNK_SIZE,
37                 chunk->pos.z * CHUNK_SIZE,
38         };
39
40         unsigned char *chunk_data[COUNT_BIOME] = {NULL};
41         bool has_biome[COUNT_BIOME] = {false};
42
43         for (s32 x = 0; x < CHUNK_SIZE; x++) {
44                 s32 pos_x = chunkp.x + x;
45
46                 for (s32 z = 0; z < CHUNK_SIZE; z++) {
47                         row_args.pos = height_args.pos = (v2s32) {pos_x, chunkp.z + z};
48
49                         condition_args.biome = get_biome(row_args.pos, &condition_args.factor);
50                         BiomeDef *biome_def = &biomes[condition_args.biome];
51
52                         height_args.factor = generate_args.factor = row_args.factor
53                                 = condition_args.factor;
54
55                         if (biome_def->chunk_data_size && !chunk_data[condition_args.biome])
56                                 chunk_data[condition_args.biome] = malloc(biome_def->chunk_data_size);
57
58                         chunk_args.chunk_data = row_args.chunk_data = height_args.chunk_data =
59                                 generate_args.chunk_data = condition_args.chunk_data =
60                                 chunk_data[condition_args.biome];
61
62                         if (!has_biome[condition_args.biome]) {
63                                 if (biome_def->before_chunk)
64                                         biome_def->before_chunk(&chunk_args);
65
66                                 has_biome[condition_args.biome] = true;
67                         }
68
69                         unsigned char row_data[biome_def->row_data_size];
70                         row_args.row_data = height_args.row_data = generate_args.row_data =
71                                 condition_args.row_data = row_data;
72
73                         if (biome_def->before_row)
74                                 biome_def->before_row(&row_args);
75
76                         height_args.height = terrain_gen_get_base_height(height_args.pos);
77                         s32 height = biome_def->height(&height_args);
78
79                         for (s32 y = 0; y < CHUNK_SIZE; y++) {
80                                 generate_args.offset = (v3s32) {x, y, z};
81
82                                 generate_args.pos = condition_args.pos = (v3s32)
83                                         {row_args.pos.x, chunkp.y + y, row_args.pos.y};
84                                 generate_args.diff = generate_args.pos.y - height;
85
86                                 generate_args.humidity = condition_args.humidity =
87                                         get_humidity(generate_args.pos);
88                                 generate_args.temperature = condition_args.temperature =
89                                         get_temperature(generate_args.pos);
90
91                                 NodeType node = biome_def->generate(&generate_args);
92
93                                 if (biome_def->snow
94                                                 && generate_args.diff <= 1
95                                                 && generate_args.temperature < 0.0
96                                                 && node == NODE_AIR)
97                                         node = NODE_SNOW;
98
99                                 if (generate_args.diff == 1) for (int i = 0; i < NUM_TREES; i++) {
100                                         TreeDef *def = &tree_def[i];
101
102                                         if (def->condition(&condition_args)
103                                                         && noise2d(condition_args.pos.x, condition_args.pos.z, 0, seed + def->offset) * 0.5 + 0.5 < def->probability
104                                                         && smooth2d(U32(condition_args.pos.x) / def->spread, U32(condition_args.pos.z) / def->spread, 0, seed + def->area_offset) * 0.5 + 0.5 < def->area_probability) {
105                                                 def->generate(condition_args.pos, changed_chunks);
106                                                 break;
107                                         }
108                                 }
109
110                                 assert(pthread_rwlock_wrlock(&chunk->lock) == 0);
111                                 if (meta->tgsb.raw.nodes[x][y][z] <= STAGE_TERRAIN) {
112                                         chunk->data[x][y][z] = server_node_create(node);
113                                         meta->tgsb.raw.nodes[x][y][z] = STAGE_TERRAIN;
114                                 }
115                                 pthread_rwlock_unlock(&chunk->lock);
116                         }
117
118                         if (biome_def->after_row)
119                                 biome_def->after_row(&row_args);
120                 }
121         }
122
123         for (Biome i = 0; i < COUNT_BIOME; i++) {
124                 if (has_biome[i]) {
125                         chunk_args.chunk_data = chunk_data[i];
126
127                         if (biomes[i].after_chunk)
128                                 biomes[i].after_chunk(&chunk_args);
129
130                         if (chunk_args.chunk_data)
131                                 free(chunk_args.chunk_data);
132                 }
133         }
134 }