diff --git a/src/cavegen.cpp b/src/cavegen.cpp index 59878c890..25e8473bc 100644 --- a/src/cavegen.cpp +++ b/src/cavegen.cpp @@ -31,23 +31,52 @@ NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0 //// CavesRandomWalk //// -CavesRandomWalk::CavesRandomWalk(Mapgen *mg, PseudoRandom *ps) +CavesRandomWalk::CavesRandomWalk( + INodeDefManager *ndef, + GenerateNotifier *gennotify, + int seed, + int water_level, + content_t water_source, + content_t lava_source) { - this->mg = mg; - this->vm = mg->vm; - this->ndef = mg->ndef; - this->water_level = mg->water_level; - this->ps = ps; - c_water_source = ndef->getId("mapgen_water_source"); - c_lava_source = ndef->getId("mapgen_lava_source"); - c_ice = ndef->getId("mapgen_ice"); + assert(ndef); + + this->ndef = ndef; + this->gennotify = gennotify; + this->seed = seed; + this->water_level = water_level; this->np_caveliquids = &nparams_caveliquids; - this->ystride = mg->csize.X; this->lava_depth = DEFAULT_LAVA_DEPTH; - if (c_ice == CONTENT_IGNORE) - c_ice = CONTENT_AIR; + c_water_source = water_source; + if (c_water_source == CONTENT_IGNORE) + c_water_source = ndef->getId("mapgen_water_source"); + if (c_water_source == CONTENT_IGNORE) + c_water_source = CONTENT_AIR; + c_lava_source = lava_source; + if (c_lava_source == CONTENT_IGNORE) + c_lava_source = ndef->getId("mapgen_lava_source"); + if (c_lava_source == CONTENT_IGNORE) + c_lava_source = CONTENT_AIR; +} + + +void CavesRandomWalk::makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax, + PseudoRandom *ps, int max_stone_height, s16 *heightmap) +{ + assert(vm); + assert(ps); + + this->vm = vm; + this->ps = ps; + this->node_min = nmin; + this->node_max = nmax; + this->heightmap = heightmap; + + this->ystride = nmax.X - nmin.X + 1; + + // Set initial parameters from randomness dswitchint = ps->range(1, 14); flooded = ps->range(1, 2) == 2; @@ -57,13 +86,7 @@ CavesRandomWalk::CavesRandomWalk(Mapgen *mg, PseudoRandom *ps) max_tunnel_diameter = ps->range(7, ps->range(8, 24)); large_cave_is_flat = (ps->range(0, 1) == 0); -} - -void CavesRandomWalk::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) -{ - node_min = nmin; - node_max = nmax; main_direction = v3f(0, 0, 0); // Allowed route area size in nodes @@ -107,18 +130,22 @@ void CavesRandomWalk::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) ); // Add generation notify begin event - v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z); - GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN; - mg->gennotify.addEvent(notifytype, abs_pos); + if (gennotify) { + v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z); + GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN; + gennotify->addEvent(notifytype, abs_pos); + } // Generate some tunnel starting from orp for (u16 j = 0; j < tunnel_routepoints; j++) makeTunnel(j % dswitchint == 0); // Add generation notify end event - abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z); - notifytype = GENNOTIFY_LARGECAVE_END; - mg->gennotify.addEvent(notifytype, abs_pos); + if (gennotify) { + v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z); + GenNotifyType notifytype = GENNOTIFY_LARGECAVE_END; + gennotify->addEvent(notifytype, abs_pos); + } } @@ -197,7 +224,7 @@ void CavesRandomWalk::carveRoute(v3f vec, float f, bool randomize_xz) startp += of; float nval = NoisePerlin3D(np_caveliquids, startp.X, - startp.Y, startp.Z, mg->seed); + startp.Y, startp.Z, seed); MapNode liquidnode = (nval < 0.40 && node_max.Y < lava_depth) ? lavanode : waternode; @@ -388,7 +415,7 @@ void CavesV6::makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax, // Add generation notify end event if (gennotify != NULL) { - v3s16 abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z); + v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z); GenNotifyType notifytype = large_cave ? GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END; gennotify->addEvent(notifytype, abs_pos); diff --git a/src/cavegen.h b/src/cavegen.h index 5a41966fe..2db5e9d4f 100644 --- a/src/cavegen.h +++ b/src/cavegen.h @@ -25,17 +25,35 @@ with this program; if not, write to the Free Software Foundation, Inc., class GenerateNotifier; +/* + CavesRandomWalk is an implementation of a cave-digging algorithm that + operates on the principle of a "random walk" to approximate the stochiastic + activity of cavern development. + + In summary, this algorithm works by carving a randomly sized tunnel in a + random direction a random amount of times, randomly varying in width. + All randomness here is uniformly distributed; alternative distributions have + not yet been implemented. + + This algorithm is very fast, executing in less than 1ms on average for an + 80x80x80 chunk of map on a modern processor. +*/ class CavesRandomWalk { public: - Mapgen *mg; MMVManip *vm; INodeDefManager *ndef; + GenerateNotifier *gennotify; s16 *heightmap; - // variables + // configurable parameters + int seed; + int water_level; int lava_depth; NoiseParams *np_caveliquids; + // intermediate state variables + u16 ystride; + s16 min_tunnel_diameter; s16 max_tunnel_diameter; u16 tunnel_routepoints; @@ -62,17 +80,26 @@ public: content_t c_water_source; content_t c_lava_source; - content_t c_ice; - int water_level; - u16 ystride; + // ndef is a mandatory parameter. + // If gennotify is NULL, generation events are not logged. + CavesRandomWalk(INodeDefManager *ndef, + GenerateNotifier *gennotify = NULL, + int seed = 0, + int water_level = 1, + content_t water_source = CONTENT_IGNORE, + content_t lava_source = CONTENT_IGNORE); - CavesRandomWalk(Mapgen *mg, PseudoRandom *ps); - void makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height); + // vm and ps are mandatory parameters. + // If heightmap is NULL, the surface level at all points is assumed to + // be water_level. + void makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax, + PseudoRandom *ps, int max_stone_height, s16 *heightmap); + +private: void makeTunnel(bool dirswitch); void carveRoute(v3f vec, float f, bool randomize_xz); -private: inline bool isPosAboveSurface(v3s16 p); }; @@ -97,11 +124,13 @@ public: PseudoRandom *ps; PseudoRandom *ps2; + // configurable parameters s16 *heightmap; content_t c_water_source; content_t c_lava_source; int water_level; + // intermediate state variables u16 ystride; s16 min_tunnel_diameter; diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 43ac6e51a..7e74ad642 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -599,8 +599,10 @@ void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth) PseudoRandom ps(blockseed + 21343); u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { - CavesRandomWalk cave(this, &ps); - cave.makeCave(node_min, node_max, max_stone_y); + CavesRandomWalk cave(ndef, &gennotify, seed, water_level, + c_water_source, CONTENT_IGNORE); + + cave.makeCave(vm, node_min, node_max, &ps, max_stone_y, heightmap); } } diff --git a/src/mapgen_valleys.cpp b/src/mapgen_valleys.cpp index 77fa1ed06..af7a8b153 100644 --- a/src/mapgen_valleys.cpp +++ b/src/mapgen_valleys.cpp @@ -841,8 +841,10 @@ void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth) if (node_max.Y <= large_cave_depth && !made_a_big_one) { u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { - CavesRandomWalk cave(this, &ps); - cave.makeCave(node_min, node_max, max_stone_y); + CavesRandomWalk cave(ndef, &gennotify, seed, water_level, + c_water_source, c_lava_source); + + cave.makeCave(vm, node_min, node_max, &ps, max_stone_y, heightmap); } } }