]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_valleys.cpp
Fix broken `BiomeGen` abstraction (#11107)
[dragonfireclient.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(MapgenValleysParams *params, EmergeParams *emerge)
58         : MapgenBasic(MAPGEN_VALLEYS, params, emerge)
59 {
60         FATAL_ERROR_IF(biomegen->getType() != BIOMEGEN_ORIGINAL,
61                 "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         small_cave_num_min = params->small_cave_num_min;
72         small_cave_num_max = params->small_cave_num_max;
73         large_cave_num_min = params->large_cave_num_min;
74         large_cave_num_max = params->large_cave_num_max;
75         large_cave_flooded = params->large_cave_flooded;
76         cavern_limit       = params->cavern_limit;
77         cavern_taper       = params->cavern_taper;
78         cavern_threshold   = params->cavern_threshold;
79         dungeon_ymin       = params->dungeon_ymin;
80         dungeon_ymax       = params->dungeon_ymax;
81
82         //// 2D Terrain noise
83         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
84         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
85         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
86         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
87         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
88         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
89
90         //// 3D Terrain noise
91         // 1-up 1-down overgeneration
92         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill,
93                 seed, csize.X, csize.Y + 2, csize.Z);
94         // 1-down overgeneraion
95         MapgenBasic::np_cave1    = params->np_cave1;
96         MapgenBasic::np_cave2    = params->np_cave2;
97         MapgenBasic::np_cavern   = params->np_cavern;
98         MapgenBasic::np_dungeons = params->np_dungeons;
99 }
100
101
102 MapgenValleys::~MapgenValleys()
103 {
104         delete noise_filler_depth;
105         delete noise_inter_valley_fill;
106         delete noise_inter_valley_slope;
107         delete noise_rivers;
108         delete noise_terrain_height;
109         delete noise_valley_depth;
110         delete noise_valley_profile;
111 }
112
113
114 MapgenValleysParams::MapgenValleysParams():
115         np_filler_depth       (0.0,   1.2,  v3f(256,  256,  256),  1605,  3, 0.5,  2.0),
116         np_inter_valley_fill  (0.0,   1.0,  v3f(256,  512,  256),  1993,  6, 0.8,  2.0),
117         np_inter_valley_slope (0.5,   0.5,  v3f(128,  128,  128),  746,   1, 1.0,  2.0),
118         np_rivers             (0.0,   1.0,  v3f(256,  256,  256),  -6050, 5, 0.6,  2.0),
119         np_terrain_height     (-10.0, 50.0, v3f(1024, 1024, 1024), 5202,  6, 0.4,  2.0),
120         np_valley_depth       (5.0,   4.0,  v3f(512,  512,  512),  -1914, 1, 1.0,  2.0),
121         np_valley_profile     (0.6,   0.50, v3f(512,  512,  512),  777,   1, 1.0,  2.0),
122         np_cave1              (0.0,   12.0, v3f(61,   61,   61),   52534, 3, 0.5,  2.0),
123         np_cave2              (0.0,   12.0, v3f(67,   67,   67),   10325, 3, 0.5,  2.0),
124         np_cavern             (0.0,   1.0,  v3f(768,  256,  768),  59033, 6, 0.63, 2.0),
125         np_dungeons           (0.9,   0.5,  v3f(500,  500,  500),  0,     2, 0.8,  2.0)
126 {
127 }
128
129
130 void MapgenValleysParams::readParams(const Settings *settings)
131 {
132         settings->getFlagStrNoEx("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
133         settings->getU16NoEx("mgvalleys_altitude_chill",       altitude_chill);
134         settings->getS16NoEx("mgvalleys_large_cave_depth",     large_cave_depth);
135         settings->getU16NoEx("mgvalleys_small_cave_num_min",   small_cave_num_min);
136         settings->getU16NoEx("mgvalleys_small_cave_num_max",   small_cave_num_max);
137         settings->getU16NoEx("mgvalleys_large_cave_num_min",   large_cave_num_min);
138         settings->getU16NoEx("mgvalleys_large_cave_num_max",   large_cave_num_max);
139         settings->getFloatNoEx("mgvalleys_large_cave_flooded", large_cave_flooded);
140         settings->getU16NoEx("mgvalleys_river_depth",          river_depth);
141         settings->getU16NoEx("mgvalleys_river_size",           river_size);
142         settings->getFloatNoEx("mgvalleys_cave_width",         cave_width);
143         settings->getS16NoEx("mgvalleys_cavern_limit",         cavern_limit);
144         settings->getS16NoEx("mgvalleys_cavern_taper",         cavern_taper);
145         settings->getFloatNoEx("mgvalleys_cavern_threshold",   cavern_threshold);
146         settings->getS16NoEx("mgvalleys_dungeon_ymin",         dungeon_ymin);
147         settings->getS16NoEx("mgvalleys_dungeon_ymax",         dungeon_ymax);
148
149         settings->getNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
150         settings->getNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
151         settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
152         settings->getNoiseParams("mgvalleys_np_rivers",             np_rivers);
153         settings->getNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
154         settings->getNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
155         settings->getNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
156
157         settings->getNoiseParams("mgvalleys_np_cave1",              np_cave1);
158         settings->getNoiseParams("mgvalleys_np_cave2",              np_cave2);
159         settings->getNoiseParams("mgvalleys_np_cavern",             np_cavern);
160         settings->getNoiseParams("mgvalleys_np_dungeons",           np_dungeons);
161 }
162
163
164 void MapgenValleysParams::writeParams(Settings *settings) const
165 {
166         settings->setFlagStr("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
167         settings->setU16("mgvalleys_altitude_chill",       altitude_chill);
168         settings->setS16("mgvalleys_large_cave_depth",     large_cave_depth);
169         settings->setU16("mgvalleys_small_cave_num_min",   small_cave_num_min);
170         settings->setU16("mgvalleys_small_cave_num_max",   small_cave_num_max);
171         settings->setU16("mgvalleys_large_cave_num_min",   large_cave_num_min);
172         settings->setU16("mgvalleys_large_cave_num_max",   large_cave_num_max);
173         settings->setFloat("mgvalleys_large_cave_flooded", large_cave_flooded);
174         settings->setU16("mgvalleys_river_depth",          river_depth);
175         settings->setU16("mgvalleys_river_size",           river_size);
176         settings->setFloat("mgvalleys_cave_width",         cave_width);
177         settings->setS16("mgvalleys_cavern_limit",         cavern_limit);
178         settings->setS16("mgvalleys_cavern_taper",         cavern_taper);
179         settings->setFloat("mgvalleys_cavern_threshold",   cavern_threshold);
180         settings->setS16("mgvalleys_dungeon_ymin",         dungeon_ymin);
181         settings->setS16("mgvalleys_dungeon_ymax",         dungeon_ymax);
182
183         settings->setNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
184         settings->setNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
185         settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
186         settings->setNoiseParams("mgvalleys_np_rivers",             np_rivers);
187         settings->setNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
188         settings->setNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
189         settings->setNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
190
191         settings->setNoiseParams("mgvalleys_np_cave1",              np_cave1);
192         settings->setNoiseParams("mgvalleys_np_cave2",              np_cave2);
193         settings->setNoiseParams("mgvalleys_np_cavern",             np_cavern);
194         settings->setNoiseParams("mgvalleys_np_dungeons",           np_dungeons);
195 }
196
197
198 void MapgenValleysParams::setDefaultSettings(Settings *settings)
199 {
200         settings->setDefault("mgvalleys_spflags", flagdesc_mapgen_valleys,
201                 MGVALLEYS_ALT_CHILL | MGVALLEYS_HUMID_RIVERS |
202                 MGVALLEYS_VARY_RIVER_DEPTH | MGVALLEYS_ALT_DRY);
203 }
204
205
206 /////////////////////////////////////////////////////////////////
207
208
209 void MapgenValleys::makeChunk(BlockMakeData *data)
210 {
211         // Pre-conditions
212         assert(data->vmanip);
213         assert(data->nodedef);
214
215         //TimeTaker t("makeChunk");
216
217         this->generating = true;
218         this->vm = data->vmanip;
219         this->ndef = data->nodedef;
220
221         v3s16 blockpos_min = data->blockpos_min;
222         v3s16 blockpos_max = data->blockpos_max;
223         node_min = blockpos_min * MAP_BLOCKSIZE;
224         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
225         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
226         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
227
228         blockseed = getBlockSeed2(full_node_min, seed);
229
230         // Generate biome noises. Note this must be executed strictly before
231         // generateTerrain, because generateTerrain depends on intermediate
232         // biome-related noises.
233         m_bgen->calcBiomeNoise(node_min);
234
235         // Generate terrain
236         s16 stone_surface_max_y = generateTerrain();
237
238         // Create heightmap
239         updateHeightmap(node_min, node_max);
240
241         // Place biome-specific nodes and build biomemap
242         if (flags & MG_BIOMES) {
243                 generateBiomes();
244         }
245
246         // Generate tunnels, caverns and large randomwalk caves
247         if (flags & MG_CAVES) {
248                 // Generate tunnels first as caverns confuse them
249                 generateCavesNoiseIntersection(stone_surface_max_y);
250
251                 // Generate caverns
252                 bool near_cavern = generateCavernsNoise(stone_surface_max_y);
253
254                 // Generate large randomwalk caves
255                 if (near_cavern)
256                         // Disable large randomwalk caves in this mapchunk by setting
257                         // 'large cave depth' to world base. Avoids excessive liquid in
258                         // large caverns and floating blobs of overgenerated liquid.
259                         generateCavesRandomWalk(stone_surface_max_y,
260                                 -MAX_MAP_GENERATION_LIMIT);
261                 else
262                         generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
263         }
264
265         // Generate the registered ores
266         if (flags & MG_ORES)
267                 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
268
269         // Dungeon creation
270         if (flags & MG_DUNGEONS)
271                 generateDungeons(stone_surface_max_y);
272
273         // Generate the registered decorations
274         if (flags & MG_DECORATIONS)
275                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
276
277         // Sprinkle some dust on top after everything else was generated
278         if (flags & MG_BIOMES)
279                 dustTopNodes();
280
281         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
282
283         if (flags & MG_LIGHT)
284                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
285                         full_node_min, full_node_max);
286
287         this->generating = false;
288
289         //printf("makeChunk: %lums\n", t.stop());
290 }
291
292
293 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
294 {
295         // Check if in a river channel
296         float n_rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
297         if (std::fabs(n_rivers) <= river_size_factor)
298                 // Unsuitable spawn point
299                 return MAX_MAP_GENERATION_LIMIT;
300
301         float n_slope          = NoisePerlin2D(&noise_inter_valley_slope->np, p.X, p.Y, seed);
302         float n_terrain_height = NoisePerlin2D(&noise_terrain_height->np, p.X, p.Y, seed);
303         float n_valley         = NoisePerlin2D(&noise_valley_depth->np, p.X, p.Y, seed);
304         float n_valley_profile = NoisePerlin2D(&noise_valley_profile->np, p.X, p.Y, seed);
305
306         float valley_d = n_valley * n_valley;
307         float base = n_terrain_height + valley_d;
308         float river = std::fabs(n_rivers) - river_size_factor;
309         float tv = std::fmax(river / n_valley_profile, 0.0f);
310         float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
311         float surface_y = base + valley_h;
312         float slope = n_slope * valley_h;
313         float river_y = base - 1.0f;
314
315         // Raising the maximum spawn level above 'water_level + 16' is necessary for custom
316         // parameters that set average terrain level much higher than water_level.
317         s16 max_spawn_y = std::fmax(
318                 noise_terrain_height->np.offset +
319                 noise_valley_depth->np.offset * noise_valley_depth->np.offset,
320                 water_level + 16);
321
322         // Starting spawn search at max_spawn_y + 128 ensures 128 nodes of open
323         // space above spawn position. Avoids spawning in possibly sealed voids.
324         for (s16 y = max_spawn_y + 128; y >= water_level; y--) {
325                 float n_fill = NoisePerlin3D(&noise_inter_valley_fill->np, p.X, y, p.Y, seed);
326                 float surface_delta = (float)y - surface_y;
327                 float density = slope * n_fill - surface_delta;
328
329                 if (density > 0.0f) {  // If solid
330                         // Sometimes surface level is below river water level in places that are not
331                         // river channels.
332                         if (y < water_level || y > max_spawn_y || y < (s16)river_y)
333                                 // Unsuitable spawn point
334                                 return MAX_MAP_GENERATION_LIMIT;
335
336                         // y + 2 because y is surface and due to biome 'dust' nodes.
337                         return y + 2;
338                 }
339         }
340         // Unsuitable spawn position, no ground found
341         return MAX_MAP_GENERATION_LIMIT;
342 }
343
344
345 int MapgenValleys::generateTerrain()
346 {
347         MapNode n_air(CONTENT_AIR);
348         MapNode n_river_water(c_river_water_source);
349         MapNode n_stone(c_stone);
350         MapNode n_water(c_water_source);
351
352         noise_inter_valley_slope->perlinMap2D(node_min.X, node_min.Z);
353         noise_rivers->perlinMap2D(node_min.X, node_min.Z);
354         noise_terrain_height->perlinMap2D(node_min.X, node_min.Z);
355         noise_valley_depth->perlinMap2D(node_min.X, node_min.Z);
356         noise_valley_profile->perlinMap2D(node_min.X, node_min.Z);
357
358         noise_inter_valley_fill->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
359
360         const v3s16 &em = vm->m_area.getExtent();
361         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
362         u32 index_2d = 0;
363
364         for (s16 z = node_min.Z; z <= node_max.Z; z++)
365         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
366                 float n_slope          = noise_inter_valley_slope->result[index_2d];
367                 float n_rivers         = noise_rivers->result[index_2d];
368                 float n_terrain_height = noise_terrain_height->result[index_2d];
369                 float n_valley         = noise_valley_depth->result[index_2d];
370                 float n_valley_profile = noise_valley_profile->result[index_2d];
371
372                 float valley_d = n_valley * n_valley;
373                 // 'base' represents the level of the river banks
374                 float base = n_terrain_height + valley_d;
375                 // 'river' represents the distance from the river edge
376                 float river = std::fabs(n_rivers) - river_size_factor;
377                 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
378                 // 'valley_h' represents the height of the terrain, from the rivers.
379                 float tv = std::fmax(river / n_valley_profile, 0.0f);
380                 float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
381                 // Approximate height of the terrain
382                 float surface_y = base + valley_h;
383                 float slope = n_slope * valley_h;
384                 // River water surface is 1 node below river banks
385                 float river_y = base - 1.0f;
386
387                 // Rivers are placed where 'river' is negative
388                 if (river < 0.0f) {
389                         // Use the function -sqrt(1-x^2) which models a circle
390                         float tr = river / river_size_factor + 1.0f;
391                         float depth = (river_depth_bed *
392                                 std::sqrt(std::fmax(0.0f, 1.0f - tr * tr)));
393                         // There is no logical equivalent to this using rangelim
394                         surface_y = std::fmin(
395                                 std::fmax(base - depth, (float)(water_level - 3)),
396                                 surface_y);
397                         slope = 0.0f;
398                 }
399
400                 // Optionally vary river depth according to heat and humidity
401                 if (spflags & MGVALLEYS_VARY_RIVER_DEPTH) {
402                         float t_heat = m_bgen->heatmap[index_2d];
403                         float heat = (spflags & MGVALLEYS_ALT_CHILL) ?
404                                 // Match heat value calculated below in
405                                 // 'Optionally decrease heat with altitude'.
406                                 // In rivers, 'ground height ignoring riverbeds' is 'base'.
407                                 // As this only affects river water we can assume y > water_level.
408                                 t_heat + 5.0f - (base - water_level) * 20.0f / altitude_chill :
409                                 t_heat;
410                         float delta = m_bgen->humidmap[index_2d] - 50.0f;
411                         if (delta < 0.0f) {
412                                 float t_evap = (heat - 32.0f) / 300.0f;
413                                 river_y += delta * std::fmax(t_evap, 0.08f);
414                         }
415                 }
416
417                 // Highest solid node in column
418                 s16 column_max_y = surface_y;
419                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
420                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
421
422                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
423                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
424                                 float n_fill = noise_inter_valley_fill->result[index_3d];
425                                 float surface_delta = (float)y - surface_y;
426                                 // Density = density noise + density gradient
427                                 float density = slope * n_fill - surface_delta;
428
429                                 if (density > 0.0f) {
430                                         vm->m_data[index_data] = n_stone; // Stone
431                                         if (y > surface_max_y)
432                                                 surface_max_y = y;
433                                         if (y > column_max_y)
434                                                 column_max_y = y;
435                                 } else if (y <= water_level) {
436                                         vm->m_data[index_data] = n_water; // Water
437                                 } else if (y <= (s16)river_y) {
438                                         vm->m_data[index_data] = n_river_water; // River water
439                                 } else {
440                                         vm->m_data[index_data] = n_air; // Air
441                                 }
442                         }
443
444                         VoxelArea::add_y(em, index_data, 1);
445                         index_3d += ystride;
446                 }
447
448                 // Optionally increase humidity around rivers
449                 if (spflags & MGVALLEYS_HUMID_RIVERS) {
450                         // Compensate to avoid increasing average humidity
451                         m_bgen->humidmap[index_2d] *= 0.8f;
452                         // Ground height ignoring riverbeds
453                         float t_alt = std::fmax(base, (float)column_max_y);
454                         float water_depth = (t_alt - base) / 4.0f;
455                         m_bgen->humidmap[index_2d] *=
456                                 1.0f + std::pow(0.5f, std::fmax(water_depth, 1.0f));
457                 }
458
459                 // Optionally decrease humidity with altitude
460                 if (spflags & MGVALLEYS_ALT_DRY) {
461                         // Ground height ignoring riverbeds
462                         float t_alt = std::fmax(base, (float)column_max_y);
463                         // Only decrease above water_level
464                         if (t_alt > water_level)
465                                 m_bgen->humidmap[index_2d] -=
466                                         (t_alt - water_level) * 10.0f / altitude_chill;
467                 }
468
469                 // Optionally decrease heat with altitude
470                 if (spflags & MGVALLEYS_ALT_CHILL) {
471                         // Compensate to avoid reducing the average heat
472                         m_bgen->heatmap[index_2d] += 5.0f;
473                         // Ground height ignoring riverbeds
474                         float t_alt = std::fmax(base, (float)column_max_y);
475                         // Only decrease above water_level
476                         if (t_alt > water_level)
477                                 m_bgen->heatmap[index_2d] -=
478                                         (t_alt - water_level) * 20.0f / altitude_chill;
479                 }
480         }
481
482         return surface_max_y;
483 }