2 #include "server/biomes.h"
3 #include "server/mapgen.h"
4 #include "server/server_map.h"
7 Biome get_biome(v2s32 pos, f64 *factor)
9 for (Biome i = 0; i < BIOME_COUNT; i++) {
10 BiomeDef *def = &biomes[i];
11 f64 f = def->probability == 1.0 ? 1.0 : (smooth2d(U32(pos.x) / def->threshold, U32(pos.y) / def->threshold, 0, seed + def->offset) * 0.5 - 0.5 + def->probability) / def->probability;
25 static s32 height_mountain(v2s32 pos, f64 factor, f32 height, unused void *row_data, unused void *block_data)
27 return pow((height + 96) * pow(((smooth2d(U32(pos.x) / 48.0, U32(pos.y) / 48.0, 0, seed + SO_MOUNTAIN_HEIGHT) + 1.0) * 256.0 + 128.0), factor), 1.0 / (factor + 1.0)) - 96;
30 static Node generate_mountain(unused v3s32 pos, s32 diff, unused f64 humidity, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, unused void *row_data, unused void *block_data)
32 return diff <= 0 ? NODE_STONE : NODE_AIR;
46 static f64 ocean_level_start[OL_COUNT] = {
64 s32 vulcano_crater_top;
68 static const f64 vulcano_radius = 256.0;
69 static const f64 vulcano_block_offset = vulcano_radius * 2.0 / MAPBLOCK_SIZE;
71 static OceanLevel get_ocean_level(f64 factor)
73 if (factor >= ocean_level_start[OL_DEEP_OCEAN])
75 else if (factor >= ocean_level_start[OL_OCEAN])
77 else if (factor >= ocean_level_start[OL_BEACH])
83 static f64 get_ocean_level_factor(f64 factor, OceanLevel level)
86 start = ocean_level_start[level];
87 end = ++level == OL_COUNT ? 1.0 : ocean_level_start[level];
89 return (factor - start) / (end - start);
92 static bool is_vulcano(v2s32 pos)
95 return noise2d(pos.x, pos.y, 0, seed + SO_VULCANO) > 0.0 && get_biome((v2s32) {pos.x * MAPBLOCK_SIZE, pos.y * MAPBLOCK_SIZE}, &factor) == BIOME_OCEAN && get_ocean_level(factor) == OL_DEEP_OCEAN;
98 static bool find_near_vulcano(v2s32 pos, v2s32 *result)
100 f64 x = pos.x / vulcano_block_offset;
101 f64 z = pos.y / vulcano_block_offset;
111 for (s32 ix = lx; ix <= hx; ix++) {
112 for (s32 iz = lz; iz <= hz; iz++) {
113 v2s32 vulcano_pos = {ix * 32, iz * 32};
115 if (is_vulcano(vulcano_pos)) {
116 *result = vulcano_pos;
125 static inline f64 min(f64 a, f64 b)
127 return a < b ? a : b;
130 static inline f64 max(f64 a, f64 b)
132 return a > b ? a : b;
135 static f64 distance(v2s32 a, v2s32 b)
137 return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
140 static s32 calculate_ocean_floor(f64 factor, s32 height)
142 switch (get_ocean_level(factor)) {
144 return f64_mix(height + 1, 0, pow(get_ocean_level_factor(factor, OL_BEACH_EDGE), 0.8));
150 return f64_mix(0, -10, pow(get_ocean_level_factor(factor, OL_OCEAN), 0.5));
153 return f64_mix(-10, -50, pow(get_ocean_level_factor(factor, OL_DEEP_OCEAN), 0.5));
162 static void preprocess_block_ocean(MapBlock *block, unused List *changed_blocks, void *block_data)
164 OceanBlockData *data = block_data;
167 if ((data->has_vulcano = find_near_vulcano((v2s32) {block->pos.x, block->pos.z}, &vulcano_pos)))
168 data->vulcano_pos = (v2s32) {vulcano_pos.x * MAPBLOCK_SIZE, vulcano_pos.y * MAPBLOCK_SIZE};
171 static void preprocess_row_ocean(v2s32 pos, unused f64 factor, void *row_data, void *block_data)
173 OceanRowData *rdata = row_data;
174 OceanBlockData *bdata = block_data;
175 rdata->vulcano = false;
177 if (bdata->has_vulcano) {
178 f64 dist = distance(pos, bdata->vulcano_pos);
180 if (dist < vulcano_radius) {
181 f64 crater_factor = pow(asin(1.0 - dist / vulcano_radius), 2.0);
182 f64 vulcano_height = (pnoise2d(U32(pos.x) / 100.0, U32(pos.y) / 100.0, 0.2, 2, seed + SO_VULCANO_HEIGHT) * 0.5 + 0.5) * 128.0 * crater_factor + 1.0 - 30.0;
183 bool is_crater = vulcano_height > 0;
186 vulcano_height = min(vulcano_height + 5.0, 0.0);
188 if (vulcano_height < 0)
189 vulcano_height *= 2.0;
191 rdata->vulcano = true;
192 rdata->vulcano_crater = is_crater;
193 rdata->vulcano_height = floor(vulcano_height + 0.5);
194 rdata->vulcano_crater_top = 50 + floor((pnoise2d(U32(pos.x) / 3.0, U32(pos.y) / 3.0, 0.0, 1, seed + SO_VULCANO_CRATER_TOP) * 0.5 + 0.5) * 3.0 + 0.5);
195 rdata->vulcano_stone = is_crater ? ((pnoise2d(U32(pos.x) / 16.0, U32(pos.y) / 16.0, 0.85, 3, seed + SO_VULCANO_STONE) * 0.5 + 0.5) * crater_factor > 0.4 ? NODE_VULCANO_STONE : NODE_STONE) : NODE_SAND;
200 static s32 height_ocean(unused v2s32 pos, f64 factor, f32 height, void *row_data, unused void *block_data)
202 OceanRowData *rdata = row_data;
203 s32 ocean_floor = calculate_ocean_floor(factor, height);
205 return rdata->vulcano ? max(ocean_floor, rdata->vulcano_height) : ocean_floor;
208 Node ocean_get_node_at(v3s32 pos, s32 diff, void *row_data)
210 OceanRowData *rdata = row_data;
212 if (rdata->vulcano && rdata->vulcano_crater) {
214 return pos.y <= 45 ? NODE_LAVA : NODE_AIR;
216 return pos.y <= rdata->vulcano_crater_top ? rdata->vulcano_stone : NODE_AIR;
231 static Node generate_ocean(v3s32 pos, s32 diff, unused f64 humidity, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, void *row_data, unused void *block_data)
233 return ocean_get_node_at(pos, diff, row_data);
238 static bool boulder_touching_ground(v3s32 pos, s32 diff)
240 for (s32 dir = diff > 0 ? -1 : +1; dir > 0 ? diff <= 0 : diff >= 0; pos.y += dir, diff += dir) {
241 if (smooth3d(U32(pos.x) / 12.0, U32(pos.y) / 6.0, U32(pos.z) / 12.0, 0, seed + SO_BOULDER) < 0.8)
248 static s32 height_hills(unused v2s32 pos, unused f64 factor, f32 height, unused void *row_data, unused void *block_data)
253 static Node generate_hills(v3s32 pos, s32 diff, unused f64 humidity, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, unused void *row_data, unused void *block_data)
255 if (boulder_touching_ground(pos, diff))
268 BiomeDef biomes[BIOME_COUNT] = {
271 .offset = SO_MOUNTAIN,
274 .height = &height_mountain,
275 .generate = &generate_mountain,
276 .block_data_size = 0,
277 .preprocess_block = NULL,
279 .preprocess_row = NULL,
286 .height = &height_ocean,
287 .generate = &generate_ocean,
288 .block_data_size = sizeof(OceanBlockData),
289 .preprocess_block = &preprocess_block_ocean,
290 .row_data_size = sizeof(OceanRowData),
291 .preprocess_row = &preprocess_row_ocean,
299 .height = &height_hills,
300 .generate = &generate_hills,
301 .block_data_size = 0,
302 .preprocess_block = NULL,
304 .preprocess_row = NULL,