Skip to content

Commit

Permalink
Cavegen/Mgv5/Mgv7: Add optional giant caverns
Browse files Browse the repository at this point in the history
Add to MapgenBasic for use by multiple mapgens.
Add to mgv5 and mgv7, enabled by default.

Similar to mgvalleys caverns but half the scale.
Parameters for upper y limit, distance caverns taper to full size, and
noise threshold (full cavern size).
As with mgvalleys caverns are generated first and classic caves are
disabled in any mapchunk containing a cavern, to avoid excessive
spreading volumes of liquids.
This also avoids floating blobs of liquid where a large classic cave
has overgenerated out into a neighbouring previously-generated mapchunk.
  • Loading branch information
paramat committed Mar 22, 2017
1 parent d4e0c0f commit 4008282
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 54 deletions.
95 changes: 95 additions & 0 deletions src/cavegen.cpp
Expand Up @@ -150,6 +150,101 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm,
}


////
//// CavernsNoise
////

CavernsNoise::CavernsNoise(
INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold)
{
assert(nodedef);

m_ndef = nodedef;

m_csize = chunksize;
m_cavern_limit = cavern_limit;
m_cavern_taper = cavern_taper;
m_cavern_threshold = cavern_threshold;

m_ystride = m_csize.X;
m_zstride_1d = m_csize.X * (m_csize.Y + 1);

// Noise is created using 1-down overgeneration
// A Nx-by-1-by-Nz-sized plane is at the bottom of the desired for
// re-carving the solid overtop placed for blocking sunlight
noise_cavern = new Noise(np_cavern, seed, m_csize.X, m_csize.Y + 1, m_csize.Z);

c_water_source = m_ndef->getId("mapgen_water_source");
if (c_water_source == CONTENT_IGNORE)
c_water_source = CONTENT_AIR;

c_lava_source = m_ndef->getId("mapgen_lava_source");
if (c_lava_source == CONTENT_IGNORE)
c_lava_source = CONTENT_AIR;
}


CavernsNoise::~CavernsNoise()
{
delete noise_cavern;
}


bool CavernsNoise::generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax)
{
assert(vm);

// Calculate noise
noise_cavern->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);

// Cache cavern_amp values
float cavern_amp[m_csize.Y + 1];
u8 cavern_amp_index = 0; // Index zero at column top
for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, cavern_amp_index++) {
cavern_amp[cavern_amp_index] =
MYMIN((m_cavern_limit - y) / (float)m_cavern_taper, 1.0f);
}

//// Place nodes
bool has_cavern = false;
v3s16 em = vm->m_area.getExtent();
u32 index2d = 0;

for (s16 z = nmin.Z; z <= nmax.Z; z++)
for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) {
// Reset cave_amp index to column top
cavern_amp_index = 0;
// Initial voxelmanip index at column top
u32 vi = vm->m_area.index(x, nmax.Y, z);
// Initial 3D noise index at column top
u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride +
(x - nmin.X);
// Don't excavate the overgenerated stone at node_max.Y + 1,
// this creates a 'roof' over the cavern, preventing light in
// caverns at mapchunk borders when generating mapchunks upwards.
// This 'roof' is excavated when the mapchunk above is generated.
for (s16 y = nmax.Y; y >= nmin.Y - 1; y--,
index3d -= m_ystride,
vm->m_area.add_y(em, vi, -1),
cavern_amp_index++) {
content_t c = vm->m_data[vi].getContent();
float nabs_cavern = fabs(noise_cavern->result[index3d]);
// Caverns generate first but still remove lava and water in case
// of overgenerated classic caves.
if (nabs_cavern * cavern_amp[cavern_amp_index] > m_cavern_threshold &&
(m_ndef->get(c).is_ground_content ||
c == c_lava_source || c == c_water_source)) {
vm->m_data[vi] = MapNode(CONTENT_AIR);
has_cavern = true;
}
}
}

return has_cavern;
}


////
//// CavesRandomWalk
////
Expand Down
30 changes: 30 additions & 0 deletions src/cavegen.h
Expand Up @@ -62,6 +62,36 @@ class CavesNoiseIntersection {
Noise *noise_cave2;
};

/*
CavernsNoise is a cave digging algorithm
*/
class CavernsNoise {
public:
CavernsNoise(INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold);
~CavernsNoise();

bool generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax);

private:
INodeDefManager *m_ndef;

// configurable parameters
v3s16 m_csize;
float m_cavern_limit;
float m_cavern_taper;
float m_cavern_threshold;

// intermediate state variables
u16 m_ystride;
u16 m_zstride_1d;

Noise *noise_cavern;

content_t c_water_source;
content_t c_lava_source;
};

/*
CavesRandomWalk is an implementation of a cave-digging algorithm that
operates on the principle of a "random walk" to approximate the stochiastic
Expand Down
12 changes: 12 additions & 0 deletions src/mapgen.cpp
Expand Up @@ -838,6 +838,18 @@ void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
}


bool MapgenBasic::generateCaverns(s16 max_stone_y)
{
if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
return false;

CavernsNoise caverns_noise(ndef, csize, &np_cavern,
seed, cavern_limit, cavern_taper, cavern_threshold);

return caverns_noise.generateCaverns(vm, node_min, node_max);
}


void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
{
if (max_stone_y < node_min.Y)
Expand Down
5 changes: 5 additions & 0 deletions src/mapgen.h
Expand Up @@ -240,6 +240,7 @@ class MapgenBasic : public Mapgen {
virtual ~MapgenBasic();

virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
virtual bool generateCaverns(s16 max_stone_y);
virtual void generateDungeons(s16 max_stone_y, MgStoneType stone_type);
virtual MgStoneType generateBiomes();
virtual void dustTopNodes();
Expand Down Expand Up @@ -279,7 +280,11 @@ class MapgenBasic : public Mapgen {

NoiseParams np_cave1;
NoiseParams np_cave2;
NoiseParams np_cavern;
float cave_width;
float cavern_limit;
float cavern_taper;
float cavern_threshold;
};

#endif
86 changes: 47 additions & 39 deletions src/mapgen_v5.cpp
Expand Up @@ -41,15 +41,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,


FlagDesc flagdesc_mapgen_v5[] = {
{NULL, 0}
{"caverns", MGV5_CAVERNS},
{NULL, 0}
};


MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
this->spflags = params->spflags;
this->cave_width = params->cave_width;
this->spflags = params->spflags;
this->cave_width = params->cave_width;
this->cavern_limit = params->cavern_limit;
this->cavern_taper = params->cavern_taper;
this->cavern_threshold = params->cavern_threshold;

// Terrain noise
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
Expand All @@ -59,9 +63,10 @@ MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
// 3D terrain noise
// 1-up 1-down overgeneration
noise_ground = new Noise(&params->np_ground, seed, csize.X, csize.Y + 2, csize.Z);

MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
// 1 down overgeneration
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
MapgenBasic::np_cavern = params->np_cavern;
}


Expand All @@ -76,47 +81,55 @@ MapgenV5::~MapgenV5()

MapgenV5Params::MapgenV5Params()
{
spflags = 0;
cave_width = 0.125;
spflags = MGV5_CAVERNS;
cave_width = 0.125;
cavern_limit = -256;
cavern_taper = 256;
cavern_threshold = 0.7;

np_filler_depth = NoiseParams(0, 1, v3f(150, 150, 150), 261, 4, 0.7, 2.0);
np_factor = NoiseParams(0, 1, v3f(250, 250, 250), 920381, 3, 0.45, 2.0);
np_height = NoiseParams(0, 10, v3f(250, 250, 250), 84174, 4, 0.5, 2.0);
np_ground = NoiseParams(0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
np_cave1 = NoiseParams(0, 12, v3f(50, 50, 50), 52534, 4, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(50, 50, 50), 10325, 4, 0.5, 2.0);
np_ground = NoiseParams(0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
np_cavern = NoiseParams(0, 1, v3f(384, 128, 384), 723, 5, 0.63, 2.0);
}


//#define CAVE_NOISE_SCALE 12.0
//#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE) = 0.125


void MapgenV5Params::readParams(const Settings *settings)
{
settings->getFlagStrNoEx("mgv5_spflags", spflags, flagdesc_mapgen_v5);
settings->getFloatNoEx("mgv5_cave_width", cave_width);
settings->getFlagStrNoEx("mgv5_spflags", spflags, flagdesc_mapgen_v5);
settings->getFloatNoEx("mgv5_cave_width", cave_width);
settings->getS16NoEx("mgv5_cavern_limit", cavern_limit);
settings->getS16NoEx("mgv5_cavern_taper", cavern_taper);
settings->getFloatNoEx("mgv5_cavern_threshold", cavern_threshold);

settings->getNoiseParams("mgv5_np_filler_depth", np_filler_depth);
settings->getNoiseParams("mgv5_np_factor", np_factor);
settings->getNoiseParams("mgv5_np_height", np_height);
settings->getNoiseParams("mgv5_np_ground", np_ground);
settings->getNoiseParams("mgv5_np_cave1", np_cave1);
settings->getNoiseParams("mgv5_np_cave2", np_cave2);
settings->getNoiseParams("mgv5_np_ground", np_ground);
settings->getNoiseParams("mgv5_np_cavern", np_cavern);
}


void MapgenV5Params::writeParams(Settings *settings) const
{
settings->setFlagStr("mgv5_spflags", spflags, flagdesc_mapgen_v5, U32_MAX);
settings->setFloat("mgv5_cave_width", cave_width);
settings->setFlagStr("mgv5_spflags", spflags, flagdesc_mapgen_v5, U32_MAX);
settings->setFloat("mgv5_cave_width", cave_width);
settings->setS16("mgv5_cavern_limit", cavern_limit);
settings->setS16("mgv5_cavern_taper", cavern_taper);
settings->setFloat("mgv5_cavern_threshold", cavern_threshold);

settings->setNoiseParams("mgv5_np_filler_depth", np_filler_depth);
settings->setNoiseParams("mgv5_np_factor", np_factor);
settings->setNoiseParams("mgv5_np_height", np_height);
settings->setNoiseParams("mgv5_np_ground", np_ground);
settings->setNoiseParams("mgv5_np_cave1", np_cave1);
settings->setNoiseParams("mgv5_np_cave2", np_cave2);
settings->setNoiseParams("mgv5_np_ground", np_ground);
settings->setNoiseParams("mgv5_np_cavern", np_cavern);
}


Expand Down Expand Up @@ -190,9 +203,21 @@ void MapgenV5::makeChunk(BlockMakeData *data)
biomegen->calcBiomeNoise(node_min);
MgStoneType stone_type = generateBiomes();

// Generate caves
if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
// Generate caverns, tunnels and classic caves
if (flags & MG_CAVES) {
bool has_cavern = false;
// Generate caverns
if (spflags & MGV5_CAVERNS)
has_cavern = generateCaverns(stone_surface_max_y);
// Generate tunnels and classic caves
if (has_cavern)
// Disable classic caves in this mapchunk by setting
// 'large cave depth' to world base. Avoids excessive liquid in
// large caverns and floating blobs of overgenerated liquid.
generateCaves(stone_surface_max_y, -MAX_MAP_GENERATION_LIMIT);
else
generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
}

// Generate dungeons and desert temples
if (flags & MG_DUNGEONS)
Expand Down Expand Up @@ -223,23 +248,6 @@ void MapgenV5::makeChunk(BlockMakeData *data)
}


//bool is_cave(u32 index) {
// double d1 = contour(noise_cave1->result[index]);
// double d2 = contour(noise_cave2->result[index]);
// return d1*d2 > CAVE_NOISE_THRESHOLD;
//}

//bool val_is_ground(v3s16 p, u32 index, u32 index2d) {
// double f = 0.55 + noise_factor->result[index2d];
// if(f < 0.01)
// f = 0.01;
// else if(f >= 1.0)
// f *= 1.6;
// double h = WATER_LEVEL + 10 * noise_height->result[index2d];
// return (noise_ground->result[index] * f > (double)p.Y - h);
//}


int MapgenV5::generateBaseTerrain()
{
u32 index = 0;
Expand Down
10 changes: 9 additions & 1 deletion src/mapgen_v5.h
Expand Up @@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#define MGV5_LARGE_CAVE_DEPTH -256

///////// Mapgen V5 flags
#define MGV5_CAVERNS 0x01

class BiomeManager;

extern FlagDesc flagdesc_mapgen_v5[];
Expand All @@ -33,12 +36,17 @@ extern FlagDesc flagdesc_mapgen_v5[];
struct MapgenV5Params : public MapgenParams {
u32 spflags;
float cave_width;
s16 cavern_limit;
s16 cavern_taper;
float cavern_threshold;

NoiseParams np_filler_depth;
NoiseParams np_factor;
NoiseParams np_height;
NoiseParams np_ground;
NoiseParams np_cave1;
NoiseParams np_cave2;
NoiseParams np_ground;
NoiseParams np_cavern;

MapgenV5Params();
~MapgenV5Params() {}
Expand Down

0 comments on commit 4008282

Please sign in to comment.