3 Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
4 Copyright (C) 2010-2015 paramat, Matt Gregory
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "content_sao.h"
30 #include "voxelalgorithms.h"
31 //#include "profiler.h" // For TimeTaker
32 #include "settings.h" // For g_settings
34 #include "dungeongen.h"
39 #include "mg_decoration.h"
40 #include "mapgen_v7.h"
43 FlagDesc flagdesc_mapgen_v7[] = {
44 {"mountains", MGV7_MOUNTAINS},
45 {"ridges", MGV7_RIDGES},
50 ///////////////////////////////////////////////////////////////////////////////
53 MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
54 : MapgenBasic(mapgenid, params, emerge)
56 MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
58 this->spflags = sp->spflags;
59 this->cave_width = sp->cave_width;
62 noise_terrain_base = new Noise(&sp->np_terrain_base, seed, csize.X, csize.Z);
63 noise_terrain_alt = new Noise(&sp->np_terrain_alt, seed, csize.X, csize.Z);
64 noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z);
65 noise_height_select = new Noise(&sp->np_height_select, seed, csize.X, csize.Z);
66 noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
67 noise_mount_height = new Noise(&sp->np_mount_height, seed, csize.X, csize.Z);
68 noise_ridge_uwater = new Noise(&sp->np_ridge_uwater, seed, csize.X, csize.Z);
71 // 1-up 1-down overgeneration
72 noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
73 noise_ridge = new Noise(&sp->np_ridge, seed, csize.X, csize.Y + 2, csize.Z);
75 MapgenBasic::np_cave1 = sp->np_cave1;
76 MapgenBasic::np_cave2 = sp->np_cave2;
82 delete noise_terrain_base;
83 delete noise_terrain_persist;
84 delete noise_height_select;
85 delete noise_terrain_alt;
86 delete noise_filler_depth;
87 delete noise_mount_height;
88 delete noise_ridge_uwater;
89 delete noise_mountain;
94 MapgenV7Params::MapgenV7Params()
96 spflags = MGV7_MOUNTAINS | MGV7_RIDGES;
99 np_terrain_base = NoiseParams(4, 70, v3f(600, 600, 600), 82341, 5, 0.6, 2.0);
100 np_terrain_alt = NoiseParams(4, 25, v3f(600, 600, 600), 5934, 5, 0.6, 2.0);
101 np_terrain_persist = NoiseParams(0.6, 0.1, v3f(2000, 2000, 2000), 539, 3, 0.6, 2.0);
102 np_height_select = NoiseParams(-8, 16, v3f(500, 500, 500), 4213, 6, 0.7, 2.0);
103 np_filler_depth = NoiseParams(0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 2.0);
104 np_mount_height = NoiseParams(256, 112, v3f(1000, 1000, 1000), 72449, 3, 0.6, 2.0);
105 np_ridge_uwater = NoiseParams(0, 1, v3f(1000, 1000, 1000), 85039, 5, 0.6, 2.0);
106 np_mountain = NoiseParams(-0.6, 1, v3f(250, 350, 250), 5333, 5, 0.63, 2.0);
107 np_ridge = NoiseParams(0, 1, v3f(100, 100, 100), 6467, 4, 0.75, 2.0);
108 np_cave1 = NoiseParams(0, 12, v3f(61, 61, 61), 52534, 3, 0.5, 2.0);
109 np_cave2 = NoiseParams(0, 12, v3f(67, 67, 67), 10325, 3, 0.5, 2.0);
113 void MapgenV7Params::readParams(const Settings *settings)
115 settings->getFlagStrNoEx("mgv7_spflags", spflags, flagdesc_mapgen_v7);
116 settings->getFloatNoEx("mgv7_cave_width", cave_width);
118 settings->getNoiseParams("mgv7_np_terrain_base", np_terrain_base);
119 settings->getNoiseParams("mgv7_np_terrain_alt", np_terrain_alt);
120 settings->getNoiseParams("mgv7_np_terrain_persist", np_terrain_persist);
121 settings->getNoiseParams("mgv7_np_height_select", np_height_select);
122 settings->getNoiseParams("mgv7_np_filler_depth", np_filler_depth);
123 settings->getNoiseParams("mgv7_np_mount_height", np_mount_height);
124 settings->getNoiseParams("mgv7_np_ridge_uwater", np_ridge_uwater);
125 settings->getNoiseParams("mgv7_np_mountain", np_mountain);
126 settings->getNoiseParams("mgv7_np_ridge", np_ridge);
127 settings->getNoiseParams("mgv7_np_cave1", np_cave1);
128 settings->getNoiseParams("mgv7_np_cave2", np_cave2);
132 void MapgenV7Params::writeParams(Settings *settings) const
134 settings->setFlagStr("mgv7_spflags", spflags, flagdesc_mapgen_v7, U32_MAX);
135 settings->setFloat("mgv7_cave_width", cave_width);
137 settings->setNoiseParams("mgv7_np_terrain_base", np_terrain_base);
138 settings->setNoiseParams("mgv7_np_terrain_alt", np_terrain_alt);
139 settings->setNoiseParams("mgv7_np_terrain_persist", np_terrain_persist);
140 settings->setNoiseParams("mgv7_np_height_select", np_height_select);
141 settings->setNoiseParams("mgv7_np_filler_depth", np_filler_depth);
142 settings->setNoiseParams("mgv7_np_mount_height", np_mount_height);
143 settings->setNoiseParams("mgv7_np_ridge_uwater", np_ridge_uwater);
144 settings->setNoiseParams("mgv7_np_mountain", np_mountain);
145 settings->setNoiseParams("mgv7_np_ridge", np_ridge);
146 settings->setNoiseParams("mgv7_np_cave1", np_cave1);
147 settings->setNoiseParams("mgv7_np_cave2", np_cave2);
151 ///////////////////////////////////////////////////////////////////////////////
154 int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
156 // Base terrain calculation
157 s16 y = baseTerrainLevelAtPoint(p.X, p.Y);
159 // Ridge/river terrain calculation
161 float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2;
162 // if inside a river this is an unsuitable spawn point
163 if (fabs(uwatern) <= width)
164 return MAX_MAP_GENERATION_LIMIT;
166 // Mountain terrain calculation
169 if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) { // Air, y is ground level
170 if (y <= water_level || y > water_level + 16)
171 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
178 // Unsuitable spawn point, no ground surface found
179 return MAX_MAP_GENERATION_LIMIT;
183 void MapgenV7::makeChunk(BlockMakeData *data)
186 assert(data->vmanip);
187 assert(data->nodedef);
188 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
189 data->blockpos_requested.Y >= data->blockpos_min.Y &&
190 data->blockpos_requested.Z >= data->blockpos_min.Z);
191 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
192 data->blockpos_requested.Y <= data->blockpos_max.Y &&
193 data->blockpos_requested.Z <= data->blockpos_max.Z);
195 this->generating = true;
196 this->vm = data->vmanip;
197 this->ndef = data->nodedef;
198 //TimeTaker t("makeChunk");
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 base and mountain terrain
210 // An initial heightmap is no longer created here for use in generateRidgeTerrain()
211 s16 stone_surface_max_y = generateTerrain();
214 if (spflags & MGV7_RIDGES)
215 generateRidgeTerrain();
218 updateHeightmap(node_min, node_max);
220 // Init biome generator, place biome-specific nodes, and build biomemap
221 biomegen->calcBiomeNoise(node_min);
222 MgStoneType stone_type = generateBiomes();
224 if (flags & MG_CAVES)
225 generateCaves(stone_surface_max_y, water_level);
227 if (flags & MG_DUNGEONS)
228 generateDungeons(stone_surface_max_y, stone_type);
230 // Generate the registered decorations
231 if (flags & MG_DECORATIONS)
232 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
234 // Generate the registered ores
235 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
237 // Sprinkle some dust on top after everything else was generated
240 //printf("makeChunk: %dms\n", t.stop());
242 updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
244 if (flags & MG_LIGHT)
245 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
246 full_node_min, full_node_max);
248 //setLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
249 // node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE, 0xFF);
251 this->generating = false;
255 float MapgenV7::baseTerrainLevelAtPoint(s16 x, s16 z)
257 float hselect = NoisePerlin2D(&noise_height_select->np, x, z, seed);
258 hselect = rangelim(hselect, 0.0, 1.0);
260 float persist = NoisePerlin2D(&noise_terrain_persist->np, x, z, seed);
262 noise_terrain_base->np.persist = persist;
263 float height_base = NoisePerlin2D(&noise_terrain_base->np, x, z, seed);
265 noise_terrain_alt->np.persist = persist;
266 float height_alt = NoisePerlin2D(&noise_terrain_alt->np, x, z, seed);
268 if (height_alt > height_base)
271 return (height_base * hselect) + (height_alt * (1.0 - hselect));
275 float MapgenV7::baseTerrainLevelFromMap(int index)
277 float hselect = rangelim(noise_height_select->result[index], 0.0, 1.0);
278 float height_base = noise_terrain_base->result[index];
279 float height_alt = noise_terrain_alt->result[index];
281 if (height_alt > height_base)
284 return (height_base * hselect) + (height_alt * (1.0 - hselect));
288 bool MapgenV7::getMountainTerrainAtPoint(s16 x, s16 y, s16 z)
290 float mnt_h_n = NoisePerlin2D(&noise_mount_height->np, x, z, seed);
291 float density_gradient = -((float)y / mnt_h_n);
292 float mnt_n = NoisePerlin3D(&noise_mountain->np, x, y, z, seed);
294 return mnt_n + density_gradient >= 0.0;
298 bool MapgenV7::getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y)
300 float mounthn = noise_mount_height->result[idx_xz];
301 float density_gradient = -((float)y / mounthn);
302 float mountn = noise_mountain->result[idx_xyz];
304 return mountn + density_gradient >= 0.0;
308 int MapgenV7::generateTerrain()
310 MapNode n_air(CONTENT_AIR);
311 MapNode n_stone(c_stone);
312 MapNode n_water(c_water_source);
314 //// Calculate noise for terrain generation
315 noise_terrain_persist->perlinMap2D(node_min.X, node_min.Z);
316 float *persistmap = noise_terrain_persist->result;
318 noise_terrain_base->perlinMap2D(node_min.X, node_min.Z, persistmap);
319 noise_terrain_alt->perlinMap2D(node_min.X, node_min.Z, persistmap);
320 noise_height_select->perlinMap2D(node_min.X, node_min.Z);
322 if (spflags & MGV7_MOUNTAINS) {
323 noise_mountain->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
324 noise_mount_height->perlinMap2D(node_min.X, node_min.Z);
328 v3s16 em = vm->m_area.getExtent();
329 s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
332 for (s16 z = node_min.Z; z <= node_max.Z; z++)
333 for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
334 s16 surface_y = baseTerrainLevelFromMap(index2d);
336 if (surface_y > stone_surface_max_y)
337 stone_surface_max_y = surface_y;
339 u32 vi = vm->m_area.index(x, node_min.Y - 1, z);
340 u32 index3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
342 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
343 if (vm->m_data[vi].getContent() == CONTENT_IGNORE) {
344 if (y <= surface_y) {
345 vm->m_data[vi] = n_stone; // Base terrain
346 } else if ((spflags & MGV7_MOUNTAINS) &&
347 getMountainTerrainFromMap(index3d, index2d, y)) {
348 vm->m_data[vi] = n_stone; // Mountain terrain
349 if (y > stone_surface_max_y)
350 stone_surface_max_y = y;
351 } else if (y <= water_level) {
352 vm->m_data[vi] = n_water;
354 vm->m_data[vi] = n_air;
357 vm->m_area.add_y(em, vi, 1);
362 return stone_surface_max_y;
366 void MapgenV7::generateRidgeTerrain()
368 if (node_max.Y < water_level - 16)
371 noise_ridge->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
372 noise_ridge_uwater->perlinMap2D(node_min.X, node_min.Z);
374 MapNode n_water(c_water_source);
375 MapNode n_air(CONTENT_AIR);
379 for (s16 z = node_min.Z; z <= node_max.Z; z++)
380 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
381 u32 vi = vm->m_area.index(node_min.X, y, z);
382 for (s16 x = node_min.X; x <= node_max.X; x++, index++, vi++) {
383 int j = (z - node_min.Z) * csize.X + (x - node_min.X);
385 float uwatern = noise_ridge_uwater->result[j] * 2;
386 if (fabs(uwatern) > width)
389 float altitude = y - water_level;
390 float height_mod = (altitude + 17) / 2.5;
391 float width_mod = width - fabs(uwatern);
392 float nridge = noise_ridge->result[index] * MYMAX(altitude, 0) / 7.0;
394 if (nridge + width_mod * height_mod < 0.6)
397 vm->m_data[vi] = (y > water_level) ? n_air : n_water;
403 ////////////////////////////////////////////////////////////////////////////////
406 //// Much of the stuff here has potential to become useful again at some point
407 //// in the future, but we don't want it to get lost or forgotten in version
412 int MapgenV7::generateMountainTerrain(s16 ymax)
414 MapNode n_stone(c_stone);
417 for (s16 z = node_min.Z; z <= node_max.Z; z++)
418 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
419 u32 vi = vm->m_area.index(node_min.X, y, z);
420 for (s16 x = node_min.X; x <= node_max.X; x++) {
421 int index = (z - node_min.Z) * csize.X + (x - node_min.X);
422 content_t c = vm->m_data[vi].getContent();
424 if (getMountainTerrainFromMap(j, index, y)
425 && (c == CONTENT_AIR || c == c_water_source)) {
426 vm->m_data[vi] = n_stone;
442 void MapgenV7::carveRivers() {
443 MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
444 MapNode n_stone(c_stone);
449 for (s16 z = node_min.Z; z <= node_max.Z; z++)
450 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
451 float terrain_mod = noise_terrain_mod->result[index];
452 NoiseParams *np = noise_terrain_river->np;
453 np.persist = noise_terrain_persist->result[index];
454 float terrain_river = NoisePerlin2DNoTxfm(np, x, z, seed);
455 float height = terrain_river * (1 - abs(terrain_mod)) *
456 noise_terrain_river->np.scale;
457 height = log(height * height); //log(h^3) is pretty interesting for terrain
459 s16 y = heightmap[index];
460 if (height < 1.0 && y > river_depth &&
461 y - river_depth >= node_min.Y && y <= node_max.Y) {
463 for (s16 ry = y; ry != y - river_depth; ry--) {
464 u32 vi = vm->m_area.index(x, ry, z);
465 vm->m_data[vi] = n_air;
468 u32 vi = vm->m_area.index(x, y - river_depth, z);
469 vm->m_data[vi] = n_water_source;
477 void MapgenV7::addTopNodes()
479 v3s16 em = vm->m_area.getExtent();
483 for (s16 z = node_min.Z; z <= node_max.Z; z++)
484 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
485 Biome *biome = bmgr->biomes[biomemap[index]];
487 //////////////////// First, add top nodes below the ridge
488 s16 y = ridge_heightmap[index];
490 // This cutoff is good enough, but not perfect.
491 // It will cut off potentially placed top nodes at chunk boundaries
494 if (y > node_max.Y) {
495 y = node_max.Y; // Let's see if we can still go downward anyway
496 u32 vi = vm->m_area.index(x, y, z);
497 content_t c = vm->m_data[vi].getContent();
498 if (ndef->get(c).walkable)
502 // N.B. It is necessary to search downward since ridge_heightmap[i]
503 // might not be the actual height, just the lowest part in the chunk
504 // where a ridge had been carved
505 u32 i = vm->m_area.index(x, y, z);
506 for (; y >= node_min.Y; y--) {
507 content_t c = vm->m_data[i].getContent();
508 if (ndef->get(c).walkable)
510 vm->m_area.add_y(em, i, -1);
513 if (y != node_min.Y - 1 && y >= water_level) {
514 ridge_heightmap[index] = y; //update ridgeheight
515 ntopnodes = biome->top_depth;
516 for (; y <= node_max.Y && ntopnodes; y++) {
518 vm->m_data[i] = MapNode(biome->c_top);
519 vm->m_area.add_y(em, i, 1);
521 // If dirt, grow grass on it.
522 if (y > water_level - 10 &&
523 vm->m_data[i].getContent() == CONTENT_AIR) {
524 vm->m_area.add_y(em, i, -1);
525 if (vm->m_data[i].getContent() == c_dirt)
526 vm->m_data[i] = MapNode(c_dirt_with_grass);
530 //////////////////// Now, add top nodes on top of the ridge
531 y = heightmap[index];
532 if (y > node_max.Y) {
533 y = node_max.Y; // Let's see if we can still go downward anyway
534 u32 vi = vm->m_area.index(x, y, z);
535 content_t c = vm->m_data[vi].getContent();
536 if (ndef->get(c).walkable)
540 i = vm->m_area.index(x, y, z);
541 for (; y >= node_min.Y; y--) {
542 content_t c = vm->m_data[i].getContent();
543 if (ndef->get(c).walkable)
545 vm->m_area.add_y(em, i, -1);
548 if (y != node_min.Y - 1) {
549 ntopnodes = biome->top_depth;
550 // Let's see if we've already added it...
551 if (y == ridge_heightmap[index] + ntopnodes - 1)
554 for (; y <= node_max.Y && ntopnodes; y++) {
556 vm->m_data[i] = MapNode(biome->c_top);
557 vm->m_area.add_y(em, i, 1);
559 // If dirt, grow grass on it.
560 if (y > water_level - 10 &&
561 vm->m_data[i].getContent() == CONTENT_AIR) {
562 vm->m_area.add_y(em, i, -1);
563 if (vm->m_data[i].getContent() == c_dirt)
564 vm->m_data[i] = MapNode(c_dirt_with_grass);