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