]> git.lizzy.rs Git - minetest.git/blob - src/mapgen/mapgen_valleys.cpp
Valleys mapgen code rewrite (#8101)
[minetest.git] / src / mapgen / mapgen_valleys.cpp
1 /*
2 Minetest
3 Copyright (C) 2016-2019 Duane Robertson <duane@duanerobertson.com>
4 Copyright (C) 2016-2019 paramat
5
6 Based on Valleys Mapgen by Gael de Sailly
7 (https://forum.minetest.net/viewtopic.php?f=9&t=11430)
8 and mapgen_v7, mapgen_flat by kwolekr and paramat.
9
10 Licensing changed by permission of Gael de Sailly.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as published by
14 the Free Software Foundation; either version 2.1 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public License along
23 with this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27
28 #include "mapgen.h"
29 #include "voxel.h"
30 #include "noise.h"
31 #include "mapblock.h"
32 #include "mapnode.h"
33 #include "map.h"
34 #include "nodedef.h"
35 #include "voxelalgorithms.h"
36 //#include "profiler.h" // For TimeTaker
37 #include "settings.h" // For g_settings
38 #include "emerge.h"
39 #include "dungeongen.h"
40 #include "mg_biome.h"
41 #include "mg_ore.h"
42 #include "mg_decoration.h"
43 #include "mapgen_valleys.h"
44 #include "cavegen.h"
45 #include <cmath>
46
47
48 FlagDesc flagdesc_mapgen_valleys[] = {
49         {"altitude_chill",   MGVALLEYS_ALT_CHILL},
50         {"humid_rivers",     MGVALLEYS_HUMID_RIVERS},
51         {"vary_river_depth", MGVALLEYS_VARY_RIVER_DEPTH},
52         {"altitude_dry",     MGVALLEYS_ALT_DRY},
53         {NULL,               0}
54 };
55
56
57 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params,
58         EmergeManager *emerge)
59         : MapgenBasic(mapgenid, params, emerge)
60 {
61         // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
62         m_bgen = (BiomeGenOriginal *)biomegen;
63
64         spflags            = params->spflags;
65         altitude_chill     = params->altitude_chill;
66         river_depth_bed    = params->river_depth + 1.0f;
67         river_size_factor  = params->river_size / 100.0f;
68
69         cave_width         = params->cave_width;
70         large_cave_depth   = params->large_cave_depth;
71         lava_depth         = params->lava_depth;
72         cavern_limit       = params->cavern_limit;
73         cavern_taper       = params->cavern_taper;
74         cavern_threshold   = params->cavern_threshold;
75         dungeon_ymin       = params->dungeon_ymin;
76         dungeon_ymax       = params->dungeon_ymax;
77
78         //// 2D Terrain noise
79         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
80         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
81         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
82         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
83         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
84         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
85
86         //// 3D Terrain noise
87         // 1-up 1-down overgeneration
88         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill,
89                 seed, csize.X, csize.Y + 2, csize.Z);
90         // 1-down overgeneraion
91         MapgenBasic::np_cave1   = params->np_cave1;
92         MapgenBasic::np_cave2   = params->np_cave2;
93         MapgenBasic::np_cavern  = params->np_cavern;
94 }
95
96
97 MapgenValleys::~MapgenValleys()
98 {
99         delete noise_filler_depth;
100         delete noise_inter_valley_fill;
101         delete noise_inter_valley_slope;
102         delete noise_rivers;
103         delete noise_terrain_height;
104         delete noise_valley_depth;
105         delete noise_valley_profile;
106 }
107
108
109 MapgenValleysParams::MapgenValleysParams():
110         np_filler_depth       (0.0,   1.2,  v3f(256,  256,  256),  1605,  3, 0.5,  2.0),
111         np_inter_valley_fill  (0.0,   1.0,  v3f(256,  512,  256),  1993,  6, 0.8,  2.0),
112         np_inter_valley_slope (0.5,   0.5,  v3f(128,  128,  128),  746,   1, 1.0,  2.0),
113         np_rivers             (0.0,   1.0,  v3f(256,  256,  256),  -6050, 5, 0.6,  2.0),
114         np_terrain_height     (-10.0, 50.0, v3f(1024, 1024, 1024), 5202,  6, 0.4,  2.0),
115         np_valley_depth       (5.0,   4.0,  v3f(512,  512,  512),  -1914, 1, 1.0,  2.0),
116         np_valley_profile     (0.6,   0.50, v3f(512,  512,  512),  777,   1, 1.0,  2.0),
117         np_cave1              (0.0,   12.0, v3f(61,   61,   61),   52534, 3, 0.5,  2.0),
118         np_cave2              (0.0,   12.0, v3f(67,   67,   67),   10325, 3, 0.5,  2.0),
119         np_cavern             (0.0,   1.0,  v3f(768,  256,  768),  59033, 6, 0.63, 2.0)
120 {
121 }
122
123
124 void MapgenValleysParams::readParams(const Settings *settings)
125 {
126         settings->getFlagStrNoEx("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys);
127         settings->getU16NoEx("mgvalleys_altitude_chill",     altitude_chill);
128         settings->getS16NoEx("mgvalleys_large_cave_depth",   large_cave_depth);
129         settings->getS16NoEx("mgvalleys_lava_depth",         lava_depth);
130         settings->getU16NoEx("mgvalleys_river_depth",        river_depth);
131         settings->getU16NoEx("mgvalleys_river_size",         river_size);
132         settings->getFloatNoEx("mgvalleys_cave_width",       cave_width);
133         settings->getS16NoEx("mgvalleys_cavern_limit",       cavern_limit);
134         settings->getS16NoEx("mgvalleys_cavern_taper",       cavern_taper);
135         settings->getFloatNoEx("mgvalleys_cavern_threshold", cavern_threshold);
136         settings->getS16NoEx("mgvalleys_dungeon_ymin",       dungeon_ymin);
137         settings->getS16NoEx("mgvalleys_dungeon_ymax",       dungeon_ymax);
138
139         settings->getNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
140         settings->getNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
141         settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
142         settings->getNoiseParams("mgvalleys_np_rivers",             np_rivers);
143         settings->getNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
144         settings->getNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
145         settings->getNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
146
147         settings->getNoiseParams("mgvalleys_np_cave1",              np_cave1);
148         settings->getNoiseParams("mgvalleys_np_cave2",              np_cave2);
149         settings->getNoiseParams("mgvalleys_np_cavern",             np_cavern);
150 }
151
152
153 void MapgenValleysParams::writeParams(Settings *settings) const
154 {
155         settings->setFlagStr("mgvalleys_spflags",        spflags, flagdesc_mapgen_valleys, U32_MAX);
156         settings->setU16("mgvalleys_altitude_chill",     altitude_chill);
157         settings->setS16("mgvalleys_large_cave_depth",   large_cave_depth);
158         settings->setS16("mgvalleys_lava_depth",         lava_depth);
159         settings->setU16("mgvalleys_river_depth",        river_depth);
160         settings->setU16("mgvalleys_river_size",         river_size);
161         settings->setFloat("mgvalleys_cave_width",       cave_width);
162         settings->setS16("mgvalleys_cavern_limit",       cavern_limit);
163         settings->setS16("mgvalleys_cavern_taper",       cavern_taper);
164         settings->setFloat("mgvalleys_cavern_threshold", cavern_threshold);
165         settings->setS16("mgvalleys_dungeon_ymin",       dungeon_ymin);
166         settings->setS16("mgvalleys_dungeon_ymax",       dungeon_ymax);
167
168         settings->setNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
169         settings->setNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
170         settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
171         settings->setNoiseParams("mgvalleys_np_rivers",             np_rivers);
172         settings->setNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
173         settings->setNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
174         settings->setNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
175
176         settings->setNoiseParams("mgvalleys_np_cave1",              np_cave1);
177         settings->setNoiseParams("mgvalleys_np_cave2",              np_cave2);
178         settings->setNoiseParams("mgvalleys_np_cavern",             np_cavern);
179 }
180
181
182 void MapgenValleys::makeChunk(BlockMakeData *data)
183 {
184         // Pre-conditions
185         assert(data->vmanip);
186         assert(data->nodedef);
187         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
188                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
189                 data->blockpos_requested.Z >= data->blockpos_min.Z);
190         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
191                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
192                 data->blockpos_requested.Z <= data->blockpos_max.Z);
193
194         //TimeTaker t("makeChunk");
195
196         this->generating = true;
197         this->vm = data->vmanip;
198         this->ndef = data->nodedef;
199
200         v3s16 blockpos_min = data->blockpos_min;
201         v3s16 blockpos_max = data->blockpos_max;
202         node_min = blockpos_min * MAP_BLOCKSIZE;
203         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
204         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
205         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
206
207         blockseed = getBlockSeed2(full_node_min, seed);
208
209         // Generate biome noises. Note this must be executed strictly before
210         // generateTerrain, because generateTerrain depends on intermediate
211         // biome-related noises.
212         m_bgen->calcBiomeNoise(node_min);
213
214         // Generate terrain
215         s16 stone_surface_max_y = generateTerrain();
216
217         // Create heightmap
218         updateHeightmap(node_min, node_max);
219
220         // Place biome-specific nodes and build biomemap
221         if (flags & MG_BIOMES) {
222                 generateBiomes();
223         }
224
225         // Generate tunnels, caverns and large randomwalk caves
226         if (flags & MG_CAVES) {
227                 // Generate tunnels first as caverns confuse them
228                 generateCavesNoiseIntersection(stone_surface_max_y);
229
230                 // Generate caverns
231                 bool near_cavern = generateCavernsNoise(stone_surface_max_y);
232
233                 // Generate large randomwalk caves
234                 if (near_cavern)
235                         // Disable large randomwalk caves in this mapchunk by setting
236                         // 'large cave depth' to world base. Avoids excessive liquid in
237                         // large caverns and floating blobs of overgenerated liquid.
238                         generateCavesRandomWalk(stone_surface_max_y,
239                                 -MAX_MAP_GENERATION_LIMIT);
240                 else
241                         generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
242         }
243
244         // Generate the registered ores
245         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
246
247         // Dungeon creation
248         if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
249                         full_node_max.Y <= dungeon_ymax)
250                 generateDungeons(stone_surface_max_y);
251
252         // Generate the registered decorations
253         if (flags & MG_DECORATIONS)
254                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
255
256         // Sprinkle some dust on top after everything else was generated
257         if (flags & MG_BIOMES)
258                 dustTopNodes();
259
260         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
261
262         if (flags & MG_LIGHT)
263                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
264                         full_node_min, full_node_max);
265
266         this->generating = false;
267
268         //printf("makeChunk: %lums\n", t.stop());
269 }
270
271
272 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
273 {
274         // Check if in a river channel
275         float n_rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
276         if (std::fabs(n_rivers) <= river_size_factor)
277                 // Unsuitable spawn point
278                 return MAX_MAP_GENERATION_LIMIT;
279
280         float n_slope          = NoisePerlin2D(&noise_inter_valley_slope->np, p.X, p.Y, seed);
281         float n_terrain_height = NoisePerlin2D(&noise_terrain_height->np, p.X, p.Y, seed);
282         float n_valley         = NoisePerlin2D(&noise_valley_depth->np, p.X, p.Y, seed);
283         float n_valley_profile = NoisePerlin2D(&noise_valley_profile->np, p.X, p.Y, seed);
284
285         float valley_d = n_valley * n_valley;
286         float base = n_terrain_height + valley_d;
287         float river = std::fabs(n_rivers) - river_size_factor;
288         float tv = std::fmax(river / n_valley_profile, 0.0f);
289         float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
290         float surface_y = base + valley_h;
291         float slope = n_slope * valley_h;
292         float river_y = base - 1.0f;
293
294         // Raising the maximum spawn level above 'water_level + 16' is necessary for custom
295         // parameters that set average terrain level much higher than water_level.
296         s16 max_spawn_y = std::fmax(
297                 noise_terrain_height->np.offset +
298                 noise_valley_depth->np.offset * noise_valley_depth->np.offset,
299                 water_level + 16);
300
301         // Starting spawn search at max_spawn_y + 128 ensures 128 nodes of open
302         // space above spawn position. Avoids spawning in possibly sealed voids.
303         for (s16 y = max_spawn_y + 128; y >= water_level; y--) {
304                 float n_fill = NoisePerlin3D(&noise_inter_valley_fill->np, p.X, y, p.Y, seed);
305                 float surface_delta = (float)y - surface_y;
306                 float density = slope * n_fill - surface_delta;
307
308                 if (density > 0.0f) {  // If solid
309                         // Sometimes surface level is below river water level in places that are not
310                         // river channels.
311                         if (y < water_level || y > max_spawn_y || y < (s16)river_y)
312                                 // Unsuitable spawn point
313                                 return MAX_MAP_GENERATION_LIMIT;
314
315                         // y + 2 because y is surface and due to biome 'dust' nodes.
316                         return y + 2;
317                 }
318         }
319         // Unsuitable spawn position, no ground found
320         return MAX_MAP_GENERATION_LIMIT;
321 }
322
323
324 int MapgenValleys::generateTerrain()
325 {
326         MapNode n_air(CONTENT_AIR);
327         MapNode n_river_water(c_river_water_source);
328         MapNode n_stone(c_stone);
329         MapNode n_water(c_water_source);
330
331         noise_inter_valley_slope->perlinMap2D(node_min.X, node_min.Z);
332         noise_rivers->perlinMap2D(node_min.X, node_min.Z);
333         noise_terrain_height->perlinMap2D(node_min.X, node_min.Z);
334         noise_valley_depth->perlinMap2D(node_min.X, node_min.Z);
335         noise_valley_profile->perlinMap2D(node_min.X, node_min.Z);
336
337         noise_inter_valley_fill->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
338
339         const v3s16 &em = vm->m_area.getExtent();
340         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
341         u32 index_2d = 0;
342
343         for (s16 z = node_min.Z; z <= node_max.Z; z++)
344         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
345                 float n_slope          = noise_inter_valley_slope->result[index_2d];
346                 float n_rivers         = noise_rivers->result[index_2d];
347                 float n_terrain_height = noise_terrain_height->result[index_2d];
348                 float n_valley         = noise_valley_depth->result[index_2d];
349                 float n_valley_profile = noise_valley_profile->result[index_2d];
350
351                 float valley_d = n_valley * n_valley;
352                 // 'base' represents the level of the river banks
353                 float base = n_terrain_height + valley_d;
354                 // 'river' represents the distance from the river edge
355                 float river = std::fabs(n_rivers) - river_size_factor;
356                 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
357                 // 'valley_h' represents the height of the terrain, from the rivers.
358                 float tv = std::fmax(river / n_valley_profile, 0.0f);
359                 float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
360                 // Approximate height of the terrain
361                 float surface_y = base + valley_h;
362                 float slope = n_slope * valley_h;
363                 // River water surface is 1 node below river banks
364                 float river_y = base - 1.0f;
365
366                 // Rivers are placed where 'river' is negative
367                 if (river < 0.0f) {
368                         // Use the the function -sqrt(1-x^2) which models a circle
369                         float tr = river / river_size_factor + 1.0f;
370                         float depth = (river_depth_bed *
371                                 std::sqrt(std::fmax(0.0f, 1.0f - tr * tr)));
372                         // There is no logical equivalent to this using rangelim
373                         surface_y = std::fmin(
374                                 std::fmax(base - depth, (float)(water_level - 3)),
375                                 surface_y);
376                         slope = 0.0f;
377                 }
378
379                 // Optionally vary river depth according to heat and humidity
380                 if (spflags & MGVALLEYS_VARY_RIVER_DEPTH) {
381                         float t_heat = m_bgen->heatmap[index_2d];
382                         float heat = (spflags & MGVALLEYS_ALT_CHILL) ?
383                                 // Match heat value calculated below in
384                                 // 'Optionally decrease heat with altitude'.
385                                 // In rivers, 'ground height ignoring riverbeds' is 'base'.
386                                 // As this only affects river water we can assume y > water_level.
387                                 t_heat + 5.0f - (base - water_level) * 20.0f / altitude_chill :
388                                 t_heat;
389                         float delta = m_bgen->humidmap[index_2d] - 50.0f;
390                         if (delta < 0.0f) {
391                                 float t_evap = (heat - 32.0f) / 300.0f;
392                                 river_y += delta * std::fmax(t_evap, 0.08f);
393                         }
394                 }
395
396                 // Highest solid node in column
397                 s16 column_max_y = surface_y;
398                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
399                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
400
401                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
402                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
403                                 float n_fill = noise_inter_valley_fill->result[index_3d];
404                                 float surface_delta = (float)y - surface_y;
405                                 // Density = density noise + density gradient
406                                 float density = slope * n_fill - surface_delta;
407
408                                 if (density > 0.0f) {
409                                         vm->m_data[index_data] = n_stone; // Stone
410                                         if (y > surface_max_y)
411                                                 surface_max_y = y;
412                                         if (y > column_max_y)
413                                                 column_max_y = y;
414                                 } else if (y <= water_level) {
415                                         vm->m_data[index_data] = n_water; // Water
416                                 } else if (y <= (s16)river_y) {
417                                         vm->m_data[index_data] = n_river_water; // River water
418                                 } else {
419                                         vm->m_data[index_data] = n_air; // Air
420                                 }
421                         }
422
423                         VoxelArea::add_y(em, index_data, 1);
424                         index_3d += ystride;
425                 }
426
427                 // Optionally increase humidity around rivers
428                 if (spflags & MGVALLEYS_HUMID_RIVERS) {
429                         // Compensate to avoid increasing average humidity
430                         m_bgen->humidmap[index_2d] *= 0.8f;
431                         // Ground height ignoring riverbeds
432                         float t_alt = std::fmax(base, (float)column_max_y);
433                         float water_depth = (t_alt - base) / 4.0f;
434                         m_bgen->humidmap[index_2d] *=
435                                 1.0f + std::pow(0.5f, std::fmax(water_depth, 1.0f));
436                 }
437
438                 // Optionally decrease humidity with altitude
439                 if (spflags & MGVALLEYS_ALT_DRY) {
440                         // Ground height ignoring riverbeds
441                         float t_alt = std::fmax(base, (float)column_max_y);
442                         // Only decrease above water_level
443                         if (t_alt > water_level)
444                                 m_bgen->humidmap[index_2d] -=
445                                         (t_alt - water_level) * 10.0f / altitude_chill;
446                 }
447
448                 // Optionally decrease heat with altitude
449                 if (spflags & MGVALLEYS_ALT_CHILL) {
450                         // Compensate to avoid reducing the average heat
451                         m_bgen->heatmap[index_2d] += 5.0f;
452                         // Ground height ignoring riverbeds
453                         float t_alt = std::fmax(base, (float)column_max_y);
454                         // Only decrease above water_level
455                         if (t_alt > water_level)
456                                 m_bgen->heatmap[index_2d] -=
457                                         (t_alt - water_level) * 20.0f / altitude_chill;
458                 }
459         }
460
461         return surface_max_y;
462 }