3 Copyright (C) 2016-2019 Duane Robertson <duane@duanerobertson.com>
4 Copyright (C) 2016-2019 paramat
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.
10 Licensing changed by permission of Gael de Sailly.
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.
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.
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.
35 #include "voxelalgorithms.h"
36 //#include "profiler.h" // For TimeTaker
37 #include "settings.h" // For g_settings
39 #include "dungeongen.h"
42 #include "mg_decoration.h"
43 #include "mapgen_valleys.h"
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},
57 MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params,
58 EmergeManager *emerge)
59 : MapgenBasic(mapgenid, params, emerge)
61 // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
62 m_bgen = (BiomeGenOriginal *)biomegen;
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;
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;
79 noise_filler_depth = new Noise(¶ms->np_filler_depth, seed, csize.X, csize.Z);
80 noise_inter_valley_slope = new Noise(¶ms->np_inter_valley_slope, seed, csize.X, csize.Z);
81 noise_rivers = new Noise(¶ms->np_rivers, seed, csize.X, csize.Z);
82 noise_terrain_height = new Noise(¶ms->np_terrain_height, seed, csize.X, csize.Z);
83 noise_valley_depth = new Noise(¶ms->np_valley_depth, seed, csize.X, csize.Z);
84 noise_valley_profile = new Noise(¶ms->np_valley_profile, seed, csize.X, csize.Z);
87 // 1-up 1-down overgeneration
88 noise_inter_valley_fill = new Noise(¶ms->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;
97 MapgenValleys::~MapgenValleys()
99 delete noise_filler_depth;
100 delete noise_inter_valley_fill;
101 delete noise_inter_valley_slope;
103 delete noise_terrain_height;
104 delete noise_valley_depth;
105 delete noise_valley_profile;
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)
124 void MapgenValleysParams::readParams(const Settings *settings)
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);
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);
147 settings->getNoiseParams("mgvalleys_np_cave1", np_cave1);
148 settings->getNoiseParams("mgvalleys_np_cave2", np_cave2);
149 settings->getNoiseParams("mgvalleys_np_cavern", np_cavern);
153 void MapgenValleysParams::writeParams(Settings *settings) const
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);
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);
176 settings->setNoiseParams("mgvalleys_np_cave1", np_cave1);
177 settings->setNoiseParams("mgvalleys_np_cave2", np_cave2);
178 settings->setNoiseParams("mgvalleys_np_cavern", np_cavern);
182 void MapgenValleys::makeChunk(BlockMakeData *data)
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);
194 //TimeTaker t("makeChunk");
196 this->generating = true;
197 this->vm = data->vmanip;
198 this->ndef = data->nodedef;
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);
207 blockseed = getBlockSeed2(full_node_min, seed);
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);
215 s16 stone_surface_max_y = generateTerrain();
218 updateHeightmap(node_min, node_max);
220 // Place biome-specific nodes and build biomemap
221 if (flags & MG_BIOMES) {
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);
231 bool near_cavern = generateCavernsNoise(stone_surface_max_y);
233 // Generate large randomwalk caves
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);
241 generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
244 // Generate the registered ores
245 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
248 if ((flags & MG_DUNGEONS) && full_node_min.Y >= dungeon_ymin &&
249 full_node_max.Y <= dungeon_ymax)
250 generateDungeons(stone_surface_max_y);
252 // Generate the registered decorations
253 if (flags & MG_DECORATIONS)
254 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
256 // Sprinkle some dust on top after everything else was generated
257 if (flags & MG_BIOMES)
260 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
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);
266 this->generating = false;
268 //printf("makeChunk: %lums\n", t.stop());
272 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
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;
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);
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;
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,
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;
308 if (density > 0.0f) { // If solid
309 // Sometimes surface level is below river water level in places that are not
311 if (y < water_level || y > max_spawn_y || y < (s16)river_y)
312 // Unsuitable spawn point
313 return MAX_MAP_GENERATION_LIMIT;
315 // y + 2 because y is surface and due to biome 'dust' nodes.
319 // Unsuitable spawn position, no ground found
320 return MAX_MAP_GENERATION_LIMIT;
324 int MapgenValleys::generateTerrain()
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);
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);
337 noise_inter_valley_fill->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
339 const v3s16 &em = vm->m_area.getExtent();
340 s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
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];
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;
366 // Rivers are placed where 'river' is negative
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)),
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 :
389 float delta = m_bgen->humidmap[index_2d] - 50.0f;
391 float t_evap = (heat - 32.0f) / 300.0f;
392 river_y += delta * std::fmax(t_evap, 0.08f);
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);
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;
408 if (density > 0.0f) {
409 vm->m_data[index_data] = n_stone; // Stone
410 if (y > surface_max_y)
412 if (y > column_max_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
419 vm->m_data[index_data] = n_air; // Air
423 VoxelArea::add_y(em, index_data, 1);
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));
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;
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;
461 return surface_max_y;