mirror of
https://github.com/minetest/minetest.git
synced 2024-12-24 23:22:24 +01:00
Mapgen: Combine generateBiomes, dustTopNodes, and generateCaves
This commit condenses the above methods into a single implementation used by V7, V5, Flat, Fractal, and Valleys mapgens and introduces MapgenBasic.
This commit is contained in:
parent
76f4856479
commit
87bc39dca7
236
src/mapgen.cpp
236
src/mapgen.cpp
@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "cavegen.h"
|
||||||
|
|
||||||
FlagDesc flagdesc_mapgen[] = {
|
FlagDesc flagdesc_mapgen[] = {
|
||||||
{"trees", MG_TREES},
|
{"trees", MG_TREES},
|
||||||
@ -369,6 +370,241 @@ void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////
|
||||||
|
//// MapgenBasic
|
||||||
|
////
|
||||||
|
|
||||||
|
MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||||
|
: Mapgen(mapgenid, params, emerge)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MgStoneType MapgenBasic::generateBiomes()
|
||||||
|
{
|
||||||
|
v3s16 em = vm->m_area.getExtent();
|
||||||
|
u32 index = 0;
|
||||||
|
MgStoneType stone_type = STONE;
|
||||||
|
|
||||||
|
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||||
|
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||||
|
Biome *biome = NULL;
|
||||||
|
u16 depth_top = 0;
|
||||||
|
u16 base_filler = 0;
|
||||||
|
u16 depth_water_top = 0;
|
||||||
|
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||||
|
|
||||||
|
// Check node at base of mapchunk above, either a node of a previously
|
||||||
|
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||||
|
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||||
|
bool air_above = c_above == CONTENT_AIR;
|
||||||
|
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
|
||||||
|
|
||||||
|
// If there is air or water above enable top/filler placement, otherwise force
|
||||||
|
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||||
|
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||||
|
|
||||||
|
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||||
|
content_t c = vm->m_data[vi].getContent();
|
||||||
|
|
||||||
|
// Biome is recalculated each time an upper surface is detected while
|
||||||
|
// working down a column. The selected biome then remains in effect for
|
||||||
|
// all nodes below until the next surface and biome recalculation.
|
||||||
|
// Biome is recalculated:
|
||||||
|
// 1. At the surface of stone below air or water.
|
||||||
|
// 2. At the surface of water below air.
|
||||||
|
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||||
|
if ((c == c_stone && (air_above || water_above || !biome))
|
||||||
|
|| ((c == c_water_source || c == c_river_water_source)
|
||||||
|
&& (air_above || !biome))) {
|
||||||
|
biome = biomegen->getBiomeAtIndex(index, y);
|
||||||
|
|
||||||
|
depth_top = biome->depth_top;
|
||||||
|
base_filler = MYMAX(depth_top
|
||||||
|
+ biome->depth_filler
|
||||||
|
+ noise_filler_depth->result[index], 0.f);
|
||||||
|
depth_water_top = biome->depth_water_top;
|
||||||
|
|
||||||
|
// Detect stone type for dungeons during every biome calculation.
|
||||||
|
// This is more efficient than detecting per-node and will not
|
||||||
|
// miss any desert stone or sandstone biomes.
|
||||||
|
if (biome->c_stone == c_desert_stone)
|
||||||
|
stone_type = DESERT_STONE;
|
||||||
|
else if (biome->c_stone == c_sandstone)
|
||||||
|
stone_type = SANDSTONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == c_stone) {
|
||||||
|
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||||
|
|
||||||
|
// If the node below isn't solid, make this node stone, so that
|
||||||
|
// any top/filler nodes above are structurally supported.
|
||||||
|
// This is done by aborting the cycle of top/filler placement
|
||||||
|
// immediately by forcing nplaced to stone level.
|
||||||
|
if (c_below == CONTENT_AIR
|
||||||
|
|| c_below == c_water_source
|
||||||
|
|| c_below == c_river_water_source)
|
||||||
|
nplaced = U16_MAX;
|
||||||
|
|
||||||
|
if (nplaced < depth_top) {
|
||||||
|
vm->m_data[vi] = MapNode(biome->c_top);
|
||||||
|
nplaced++;
|
||||||
|
} else if (nplaced < base_filler) {
|
||||||
|
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||||
|
nplaced++;
|
||||||
|
} else {
|
||||||
|
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||||
|
}
|
||||||
|
|
||||||
|
air_above = false;
|
||||||
|
water_above = false;
|
||||||
|
} else if (c == c_water_source) {
|
||||||
|
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
|
||||||
|
? biome->c_water_top : biome->c_water);
|
||||||
|
nplaced = 0; // Enable top/filler placement for next surface
|
||||||
|
air_above = false;
|
||||||
|
water_above = true;
|
||||||
|
} else if (c == c_river_water_source) {
|
||||||
|
vm->m_data[vi] = MapNode(biome->c_river_water);
|
||||||
|
nplaced = depth_top; // Enable filler placement for next surface
|
||||||
|
air_above = false;
|
||||||
|
water_above = true;
|
||||||
|
} else if (c == CONTENT_AIR) {
|
||||||
|
nplaced = 0; // Enable top/filler placement for next surface
|
||||||
|
air_above = true;
|
||||||
|
water_above = false;
|
||||||
|
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||||
|
nplaced = U16_MAX; // Disable top/filler placement
|
||||||
|
air_above = false;
|
||||||
|
water_above = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->m_area.add_y(em, vi, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stone_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MapgenBasic::dustTopNodes()
|
||||||
|
{
|
||||||
|
if (node_max.Y < water_level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
v3s16 em = vm->m_area.getExtent();
|
||||||
|
u32 index = 0;
|
||||||
|
|
||||||
|
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||||
|
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||||
|
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
||||||
|
|
||||||
|
if (biome->c_dust == CONTENT_IGNORE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||||
|
content_t c_full_max = vm->m_data[vi].getContent();
|
||||||
|
s16 y_start;
|
||||||
|
|
||||||
|
if (c_full_max == CONTENT_AIR) {
|
||||||
|
y_start = full_node_max.Y - 1;
|
||||||
|
} else if (c_full_max == CONTENT_IGNORE) {
|
||||||
|
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||||
|
content_t c_max = vm->m_data[vi].getContent();
|
||||||
|
|
||||||
|
if (c_max == CONTENT_AIR)
|
||||||
|
y_start = node_max.Y;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vi = vm->m_area.index(x, y_start, z);
|
||||||
|
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||||
|
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
vm->m_area.add_y(em, vi, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
content_t c = vm->m_data[vi].getContent();
|
||||||
|
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||||
|
vm->m_area.add_y(em, vi, 1);
|
||||||
|
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
|
||||||
|
{
|
||||||
|
if (max_stone_y < node_min.Y)
|
||||||
|
return;
|
||||||
|
|
||||||
|
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||||
|
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||||
|
|
||||||
|
v3s16 em = vm->m_area.getExtent();
|
||||||
|
u32 index2d = 0;
|
||||||
|
|
||||||
|
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||||
|
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
||||||
|
bool column_is_open = false; // Is column open to overground
|
||||||
|
bool is_tunnel = false; // Is tunnel or tunnel floor
|
||||||
|
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||||
|
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
||||||
|
(x - node_min.X);
|
||||||
|
// Biome of column
|
||||||
|
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
||||||
|
|
||||||
|
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
||||||
|
// this creates a 'roof' over the tunnel, preventing light in
|
||||||
|
// tunnels at mapchunk borders when generating mapchunks upwards.
|
||||||
|
// This 'roof' is removed when the mapchunk above is generated.
|
||||||
|
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
||||||
|
index3d -= ystride,
|
||||||
|
vm->m_area.add_y(em, vi, -1)) {
|
||||||
|
|
||||||
|
content_t c = vm->m_data[vi].getContent();
|
||||||
|
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
||||||
|
c == biome->c_water) {
|
||||||
|
column_is_open = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Ground
|
||||||
|
float d1 = contour(noise_cave1->result[index3d]);
|
||||||
|
float d2 = contour(noise_cave2->result[index3d]);
|
||||||
|
|
||||||
|
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
||||||
|
// In tunnel and ground content, excavate
|
||||||
|
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
||||||
|
is_tunnel = true;
|
||||||
|
} else {
|
||||||
|
// Not in tunnel or not ground content
|
||||||
|
if (is_tunnel && column_is_open &&
|
||||||
|
(c == biome->c_filler || c == biome->c_stone))
|
||||||
|
// Tunnel entrance floor
|
||||||
|
vm->m_data[vi] = MapNode(biome->c_top);
|
||||||
|
|
||||||
|
column_is_open = false;
|
||||||
|
is_tunnel = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_max.Y > large_cave_depth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PseudoRandom ps(blockseed + 21343);
|
||||||
|
u32 bruises_count = ps.range(0, 2);
|
||||||
|
for (u32 i = 0; i < bruises_count; i++) {
|
||||||
|
CaveV5 cave(this, &ps); ////caves version varies ---- todo- fix this!
|
||||||
|
cave.makeCave(node_min, node_max, max_stone_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////
|
////
|
||||||
//// GenerateNotifier
|
//// GenerateNotifier
|
||||||
////
|
////
|
||||||
|
56
src/mapgen.h
56
src/mapgen.h
@ -46,6 +46,7 @@ extern FlagDesc flagdesc_gennotify[];
|
|||||||
class Biome;
|
class Biome;
|
||||||
class BiomeGen;
|
class BiomeGen;
|
||||||
struct BiomeParams;
|
struct BiomeParams;
|
||||||
|
class BiomeManager;
|
||||||
class EmergeManager;
|
class EmergeManager;
|
||||||
class MapBlock;
|
class MapBlock;
|
||||||
class VoxelManipulator;
|
class VoxelManipulator;
|
||||||
@ -137,6 +138,16 @@ struct MapgenParams {
|
|||||||
void save(Settings &settings) const;
|
void save(Settings &settings) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generic interface for map generators. All mapgens must inherit this class.
|
||||||
|
If a feature exposed by a public member pointer is not supported by a
|
||||||
|
certain mapgen, it must be set to NULL.
|
||||||
|
|
||||||
|
Apart from makeChunk, getGroundLevelAtPoint, and getSpawnLevelAtPoint, all
|
||||||
|
methods can be used by constructing a Mapgen base class and setting the
|
||||||
|
appropriate public members (e.g. vm, ndef, and so on).
|
||||||
|
*/
|
||||||
class Mapgen {
|
class Mapgen {
|
||||||
public:
|
public:
|
||||||
int seed;
|
int seed;
|
||||||
@ -189,6 +200,51 @@ private:
|
|||||||
DISABLE_CLASS_COPY(Mapgen);
|
DISABLE_CLASS_COPY(Mapgen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
MapgenBasic is a Mapgen implementation that handles basic functionality
|
||||||
|
the majority of conventional mapgens will probably want to use, but isn't
|
||||||
|
generic enough to be included as part of the base Mapgen class (such as
|
||||||
|
generating biome terrain over terrain node skeletons, generating caves,
|
||||||
|
dungeons, etc.)
|
||||||
|
|
||||||
|
Inherit MapgenBasic instead of Mapgen to add this basic functionality to
|
||||||
|
your mapgen without having to reimplement it. Feel free to override any of
|
||||||
|
these methods if you desire different or more advanced behavior.
|
||||||
|
|
||||||
|
Note that you must still create your own generateTerrain implementation when
|
||||||
|
inheriting MapgenBasic.
|
||||||
|
*/
|
||||||
|
class MapgenBasic : public Mapgen {
|
||||||
|
public:
|
||||||
|
EmergeManager *m_emerge;
|
||||||
|
BiomeManager *bmgr;
|
||||||
|
|
||||||
|
Noise *noise_filler_depth;
|
||||||
|
Noise *noise_cave1;
|
||||||
|
Noise *noise_cave2;
|
||||||
|
|
||||||
|
v3s16 node_min;
|
||||||
|
v3s16 node_max;
|
||||||
|
v3s16 full_node_min;
|
||||||
|
v3s16 full_node_max;
|
||||||
|
|
||||||
|
content_t c_stone;
|
||||||
|
content_t c_water_source;
|
||||||
|
content_t c_river_water_source;
|
||||||
|
content_t c_desert_stone;
|
||||||
|
content_t c_sandstone;
|
||||||
|
|
||||||
|
int ystride;
|
||||||
|
int zstride_1d;
|
||||||
|
float cave_width;
|
||||||
|
|
||||||
|
MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||||
|
|
||||||
|
virtual MgStoneType generateBiomes();
|
||||||
|
virtual void dustTopNodes();
|
||||||
|
virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
|
||||||
|
};
|
||||||
|
|
||||||
struct MapgenFactory {
|
struct MapgenFactory {
|
||||||
virtual Mapgen *createMapgen(int mgid, MapgenParams *params,
|
virtual Mapgen *createMapgen(int mgid, MapgenParams *params,
|
||||||
EmergeManager *emerge) = 0;
|
EmergeManager *emerge) = 0;
|
||||||
|
@ -50,7 +50,7 @@ FlagDesc flagdesc_mapgen_flat[] = {
|
|||||||
|
|
||||||
|
|
||||||
MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||||
: Mapgen(mapgenid, params, emerge)
|
: MapgenBasic(mapgenid, params, emerge)
|
||||||
{
|
{
|
||||||
this->m_emerge = emerge;
|
this->m_emerge = emerge;
|
||||||
this->bmgr = emerge->biomemgr;
|
this->bmgr = emerge->biomemgr;
|
||||||
@ -248,7 +248,7 @@ void MapgenFlat::makeChunk(BlockMakeData *data)
|
|||||||
MgStoneType stone_type = generateBiomes();
|
MgStoneType stone_type = generateBiomes();
|
||||||
|
|
||||||
if (flags & MG_CAVES)
|
if (flags & MG_CAVES)
|
||||||
generateCaves(stone_surface_max_y);
|
generateCaves(stone_surface_max_y, large_cave_depth);
|
||||||
|
|
||||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||||
DungeonParams dp;
|
DungeonParams dp;
|
||||||
@ -381,220 +381,3 @@ s16 MapgenFlat::generateTerrain()
|
|||||||
|
|
||||||
return stone_surface_max_y;
|
return stone_surface_max_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MgStoneType MapgenFlat::generateBiomes()
|
|
||||||
{
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
MgStoneType stone_type = STONE;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = NULL;
|
|
||||||
u16 depth_top = 0;
|
|
||||||
u16 base_filler = 0;
|
|
||||||
u16 depth_water_top = 0;
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
|
|
||||||
// Check node at base of mapchunk above, either a node of a previously
|
|
||||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
|
||||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
|
||||||
bool air_above = c_above == CONTENT_AIR;
|
|
||||||
bool water_above = c_above == c_water_source;
|
|
||||||
|
|
||||||
// If there is air or water above enable top/filler placement, otherwise force
|
|
||||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
|
||||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
|
||||||
|
|
||||||
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
// Biome is recalculated each time an upper surface is detected while
|
|
||||||
// working down a column. The selected biome then remains in effect for
|
|
||||||
// all nodes below until the next surface and biome recalculation.
|
|
||||||
// Biome is recalculated:
|
|
||||||
// 1. At the surface of stone below air or water.
|
|
||||||
// 2. At the surface of water below air.
|
|
||||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
|
||||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
|
||||||
(c == c_water_source && (air_above || !biome))) {
|
|
||||||
biome = biomegen->getBiomeAtIndex(index, y);
|
|
||||||
|
|
||||||
depth_top = biome->depth_top;
|
|
||||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
|
||||||
+ noise_filler_depth->result[index], 0);
|
|
||||||
depth_water_top = biome->depth_water_top;
|
|
||||||
|
|
||||||
// Detect stone type for dungeons during every biome calculation.
|
|
||||||
// This is more efficient than detecting per-node and will not
|
|
||||||
// miss any desert stone or sandstone biomes.
|
|
||||||
if (biome->c_stone == c_desert_stone)
|
|
||||||
stone_type = DESERT_STONE;
|
|
||||||
else if (biome->c_stone == c_sandstone)
|
|
||||||
stone_type = SANDSTONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == c_stone) {
|
|
||||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
|
||||||
|
|
||||||
// If the node below isn't solid, make this node stone, so that
|
|
||||||
// any top/filler nodes above are structurally supported.
|
|
||||||
// This is done by aborting the cycle of top/filler placement
|
|
||||||
// immediately by forcing nplaced to stone level.
|
|
||||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
|
||||||
nplaced = U16_MAX;
|
|
||||||
|
|
||||||
if (nplaced < depth_top) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
nplaced++;
|
|
||||||
} else if (nplaced < base_filler) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
|
||||||
nplaced++;
|
|
||||||
} else {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
|
||||||
}
|
|
||||||
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
} else if (c == c_water_source) {
|
|
||||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
|
||||||
biome->c_water_top : biome->c_water);
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = false;
|
|
||||||
water_above = true;
|
|
||||||
} else if (c == CONTENT_AIR) {
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = true;
|
|
||||||
water_above = false;
|
|
||||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
|
||||||
nplaced = U16_MAX; // Disable top/filler placement
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stone_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenFlat::dustTopNodes()
|
|
||||||
{
|
|
||||||
if (node_max.Y < water_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
|
||||||
|
|
||||||
if (biome->c_dust == CONTENT_IGNORE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
|
||||||
content_t c_full_max = vm->m_data[vi].getContent();
|
|
||||||
s16 y_start;
|
|
||||||
|
|
||||||
if (c_full_max == CONTENT_AIR) {
|
|
||||||
y_start = full_node_max.Y - 1;
|
|
||||||
} else if (c_full_max == CONTENT_IGNORE) {
|
|
||||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
|
||||||
content_t c_max = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
if (c_max == CONTENT_AIR)
|
|
||||||
y_start = node_max.Y;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi = vm->m_area.index(x, y_start, z);
|
|
||||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
|
||||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
|
||||||
vm->m_area.add_y(em, vi, 1);
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenFlat::generateCaves(s16 max_stone_y)
|
|
||||||
{
|
|
||||||
if (max_stone_y < node_min.Y)
|
|
||||||
return;
|
|
||||||
|
|
||||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index2d = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
|
||||||
bool column_is_open = false; // Is column open to overground
|
|
||||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
|
||||||
(x - node_min.X);
|
|
||||||
// Biome of column
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
|
||||||
|
|
||||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
|
||||||
// this creates a 'roof' over the tunnel, preventing light in
|
|
||||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
|
||||||
// This 'roof' is removed when the mapchunk above is generated.
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
|
||||||
index3d -= ystride,
|
|
||||||
vm->m_area.add_y(em, vi, -1)) {
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
|
||||||
c == biome->c_water) {
|
|
||||||
column_is_open = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Ground
|
|
||||||
float d1 = contour(noise_cave1->result[index3d]);
|
|
||||||
float d2 = contour(noise_cave2->result[index3d]);
|
|
||||||
|
|
||||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
|
||||||
// In tunnel and ground content, excavate
|
|
||||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
|
||||||
is_tunnel = true;
|
|
||||||
} else {
|
|
||||||
// Not in tunnel or not ground content
|
|
||||||
if (is_tunnel && column_is_open &&
|
|
||||||
(c == biome->c_filler || c == biome->c_stone))
|
|
||||||
// Tunnel entrance floor
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
|
|
||||||
column_is_open = false;
|
|
||||||
is_tunnel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_max.Y > large_cave_depth)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PseudoRandom ps(blockseed + 21343);
|
|
||||||
u32 bruises_count = ps.range(0, 2);
|
|
||||||
for (u32 i = 0; i < bruises_count; i++) {
|
|
||||||
CaveV5 cave(this, &ps);
|
|
||||||
cave.makeCave(node_min, node_max, max_stone_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -53,43 +53,19 @@ struct MapgenFlatParams : public MapgenSpecificParams {
|
|||||||
void writeParams(Settings *settings) const;
|
void writeParams(Settings *settings) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapgenFlat : public Mapgen {
|
class MapgenFlat : public MapgenBasic {
|
||||||
public:
|
public:
|
||||||
EmergeManager *m_emerge;
|
|
||||||
BiomeManager *bmgr;
|
|
||||||
|
|
||||||
int ystride;
|
|
||||||
int zstride_1d;
|
|
||||||
|
|
||||||
v3s16 node_min;
|
|
||||||
v3s16 node_max;
|
|
||||||
v3s16 full_node_min;
|
|
||||||
v3s16 full_node_max;
|
|
||||||
|
|
||||||
u32 spflags;
|
u32 spflags;
|
||||||
s16 ground_level;
|
s16 ground_level;
|
||||||
s16 large_cave_depth;
|
s16 large_cave_depth;
|
||||||
float cave_width;
|
|
||||||
float lake_threshold;
|
float lake_threshold;
|
||||||
float lake_steepness;
|
float lake_steepness;
|
||||||
float hill_threshold;
|
float hill_threshold;
|
||||||
float hill_steepness;
|
float hill_steepness;
|
||||||
Noise *noise_terrain;
|
Noise *noise_terrain;
|
||||||
Noise *noise_filler_depth;
|
|
||||||
Noise *noise_cave1;
|
|
||||||
Noise *noise_cave2;
|
|
||||||
|
|
||||||
Noise *noise_heat;
|
|
||||||
Noise *noise_humidity;
|
|
||||||
Noise *noise_heat_blend;
|
|
||||||
Noise *noise_humidity_blend;
|
|
||||||
|
|
||||||
content_t c_stone;
|
|
||||||
content_t c_water_source;
|
|
||||||
content_t c_lava_source;
|
content_t c_lava_source;
|
||||||
content_t c_desert_stone;
|
|
||||||
content_t c_ice;
|
content_t c_ice;
|
||||||
content_t c_sandstone;
|
|
||||||
|
|
||||||
content_t c_cobble;
|
content_t c_cobble;
|
||||||
content_t c_stair_cobble;
|
content_t c_stair_cobble;
|
||||||
@ -104,9 +80,6 @@ public:
|
|||||||
int getSpawnLevelAtPoint(v2s16 p);
|
int getSpawnLevelAtPoint(v2s16 p);
|
||||||
void calculateNoise();
|
void calculateNoise();
|
||||||
s16 generateTerrain();
|
s16 generateTerrain();
|
||||||
MgStoneType generateBiomes();
|
|
||||||
void dustTopNodes();
|
|
||||||
void generateCaves(s16 max_stone_y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MapgenFactoryFlat : public MapgenFactory {
|
struct MapgenFactoryFlat : public MapgenFactory {
|
||||||
|
@ -48,7 +48,7 @@ FlagDesc flagdesc_mapgen_fractal[] = {
|
|||||||
|
|
||||||
|
|
||||||
MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||||
: Mapgen(mapgenid, params, emerge)
|
: MapgenBasic(mapgenid, params, emerge)
|
||||||
{
|
{
|
||||||
this->m_emerge = emerge;
|
this->m_emerge = emerge;
|
||||||
this->bmgr = emerge->biomemgr;
|
this->bmgr = emerge->biomemgr;
|
||||||
@ -264,7 +264,7 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
|
|||||||
MgStoneType stone_type = generateBiomes();
|
MgStoneType stone_type = generateBiomes();
|
||||||
|
|
||||||
if (flags & MG_CAVES)
|
if (flags & MG_CAVES)
|
||||||
generateCaves(stone_surface_max_y);
|
generateCaves(stone_surface_max_y, MGFRACTAL_LARGE_CAVE_DEPTH);
|
||||||
|
|
||||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||||
DungeonParams dp;
|
DungeonParams dp;
|
||||||
@ -505,220 +505,3 @@ s16 MapgenFractal::generateTerrain()
|
|||||||
|
|
||||||
return stone_surface_max_y;
|
return stone_surface_max_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MgStoneType MapgenFractal::generateBiomes()
|
|
||||||
{
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
MgStoneType stone_type = STONE;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = NULL;
|
|
||||||
u16 depth_top = 0;
|
|
||||||
u16 base_filler = 0;
|
|
||||||
u16 depth_water_top = 0;
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
|
|
||||||
// Check node at base of mapchunk above, either a node of a previously
|
|
||||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
|
||||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
|
||||||
bool air_above = c_above == CONTENT_AIR;
|
|
||||||
bool water_above = c_above == c_water_source;
|
|
||||||
|
|
||||||
// If there is air or water above enable top/filler placement, otherwise force
|
|
||||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
|
||||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
|
||||||
|
|
||||||
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
// Biome is recalculated each time an upper surface is detected while
|
|
||||||
// working down a column. The selected biome then remains in effect for
|
|
||||||
// all nodes below until the next surface and biome recalculation.
|
|
||||||
// Biome is recalculated:
|
|
||||||
// 1. At the surface of stone below air or water.
|
|
||||||
// 2. At the surface of water below air.
|
|
||||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
|
||||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
|
||||||
(c == c_water_source && (air_above || !biome))) {
|
|
||||||
biome = biomegen->getBiomeAtIndex(index, y);
|
|
||||||
|
|
||||||
depth_top = biome->depth_top;
|
|
||||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
|
||||||
+ noise_filler_depth->result[index], 0);
|
|
||||||
depth_water_top = biome->depth_water_top;
|
|
||||||
|
|
||||||
// Detect stone type for dungeons during every biome calculation.
|
|
||||||
// This is more efficient than detecting per-node and will not
|
|
||||||
// miss any desert stone or sandstone biomes.
|
|
||||||
if (biome->c_stone == c_desert_stone)
|
|
||||||
stone_type = DESERT_STONE;
|
|
||||||
else if (biome->c_stone == c_sandstone)
|
|
||||||
stone_type = SANDSTONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == c_stone) {
|
|
||||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
|
||||||
|
|
||||||
// If the node below isn't solid, make this node stone, so that
|
|
||||||
// any top/filler nodes above are structurally supported.
|
|
||||||
// This is done by aborting the cycle of top/filler placement
|
|
||||||
// immediately by forcing nplaced to stone level.
|
|
||||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
|
||||||
nplaced = U16_MAX;
|
|
||||||
|
|
||||||
if (nplaced < depth_top) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
nplaced++;
|
|
||||||
} else if (nplaced < base_filler) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
|
||||||
nplaced++;
|
|
||||||
} else {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
|
||||||
}
|
|
||||||
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
} else if (c == c_water_source) {
|
|
||||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
|
||||||
biome->c_water_top : biome->c_water);
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = false;
|
|
||||||
water_above = true;
|
|
||||||
} else if (c == CONTENT_AIR) {
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = true;
|
|
||||||
water_above = false;
|
|
||||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
|
||||||
nplaced = U16_MAX; // Disable top/filler placement
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stone_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenFractal::dustTopNodes()
|
|
||||||
{
|
|
||||||
if (node_max.Y < water_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
|
||||||
|
|
||||||
if (biome->c_dust == CONTENT_IGNORE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
|
||||||
content_t c_full_max = vm->m_data[vi].getContent();
|
|
||||||
s16 y_start;
|
|
||||||
|
|
||||||
if (c_full_max == CONTENT_AIR) {
|
|
||||||
y_start = full_node_max.Y - 1;
|
|
||||||
} else if (c_full_max == CONTENT_IGNORE) {
|
|
||||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
|
||||||
content_t c_max = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
if (c_max == CONTENT_AIR)
|
|
||||||
y_start = node_max.Y;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi = vm->m_area.index(x, y_start, z);
|
|
||||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
|
||||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
|
||||||
vm->m_area.add_y(em, vi, 1);
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenFractal::generateCaves(s16 max_stone_y)
|
|
||||||
{
|
|
||||||
if (max_stone_y < node_min.Y)
|
|
||||||
return;
|
|
||||||
|
|
||||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index2d = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
|
||||||
bool column_is_open = false; // Is column open to overground
|
|
||||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
|
||||||
(x - node_min.X);
|
|
||||||
// Biome of column
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
|
||||||
|
|
||||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
|
||||||
// this creates a 'roof' over the tunnel, preventing light in
|
|
||||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
|
||||||
// This 'roof' is removed when the mapchunk above is generated.
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
|
||||||
index3d -= ystride,
|
|
||||||
vm->m_area.add_y(em, vi, -1)) {
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
|
||||||
c == biome->c_water) {
|
|
||||||
column_is_open = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Ground
|
|
||||||
float d1 = contour(noise_cave1->result[index3d]);
|
|
||||||
float d2 = contour(noise_cave2->result[index3d]);
|
|
||||||
|
|
||||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
|
||||||
// In tunnel and ground content, excavate
|
|
||||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
|
||||||
is_tunnel = true;
|
|
||||||
} else {
|
|
||||||
// Not in tunnel or not ground content
|
|
||||||
if (is_tunnel && column_is_open &&
|
|
||||||
(c == biome->c_filler || c == biome->c_stone))
|
|
||||||
// Tunnel entrance floor
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
|
|
||||||
column_is_open = false;
|
|
||||||
is_tunnel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_max.Y > MGFRACTAL_LARGE_CAVE_DEPTH)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PseudoRandom ps(blockseed + 21343);
|
|
||||||
u32 bruises_count = ps.range(0, 2);
|
|
||||||
for (u32 i = 0; i < bruises_count; i++) {
|
|
||||||
CaveV5 cave(this, &ps);
|
|
||||||
cave.makeCave(node_min, node_max, max_stone_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -57,23 +57,12 @@ struct MapgenFractalParams : public MapgenSpecificParams {
|
|||||||
void writeParams(Settings *settings) const;
|
void writeParams(Settings *settings) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapgenFractal : public Mapgen {
|
class MapgenFractal : public MapgenBasic {
|
||||||
public:
|
public:
|
||||||
EmergeManager *m_emerge;
|
|
||||||
BiomeManager *bmgr;
|
|
||||||
|
|
||||||
int ystride;
|
|
||||||
int zstride_1d;
|
|
||||||
u16 formula;
|
u16 formula;
|
||||||
bool julia;
|
bool julia;
|
||||||
|
|
||||||
v3s16 node_min;
|
|
||||||
v3s16 node_max;
|
|
||||||
v3s16 full_node_min;
|
|
||||||
v3s16 full_node_max;
|
|
||||||
|
|
||||||
u32 spflags;
|
u32 spflags;
|
||||||
float cave_width;
|
|
||||||
u16 fractal;
|
u16 fractal;
|
||||||
u16 iterations;
|
u16 iterations;
|
||||||
v3f scale;
|
v3f scale;
|
||||||
@ -84,16 +73,9 @@ public:
|
|||||||
float julia_z;
|
float julia_z;
|
||||||
float julia_w;
|
float julia_w;
|
||||||
Noise *noise_seabed;
|
Noise *noise_seabed;
|
||||||
Noise *noise_filler_depth;
|
|
||||||
Noise *noise_cave1;
|
|
||||||
Noise *noise_cave2;
|
|
||||||
|
|
||||||
content_t c_stone;
|
|
||||||
content_t c_water_source;
|
|
||||||
content_t c_lava_source;
|
content_t c_lava_source;
|
||||||
content_t c_desert_stone;
|
|
||||||
content_t c_ice;
|
content_t c_ice;
|
||||||
content_t c_sandstone;
|
|
||||||
|
|
||||||
content_t c_cobble;
|
content_t c_cobble;
|
||||||
content_t c_stair_cobble;
|
content_t c_stair_cobble;
|
||||||
@ -109,9 +91,6 @@ public:
|
|||||||
void calculateNoise();
|
void calculateNoise();
|
||||||
bool getFractalAtPoint(s16 x, s16 y, s16 z);
|
bool getFractalAtPoint(s16 x, s16 y, s16 z);
|
||||||
s16 generateTerrain();
|
s16 generateTerrain();
|
||||||
MgStoneType generateBiomes();
|
|
||||||
void dustTopNodes();
|
|
||||||
void generateCaves(s16 max_stone_y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MapgenFactoryFractal : public MapgenFactory {
|
struct MapgenFactoryFractal : public MapgenFactory {
|
||||||
|
@ -46,7 +46,7 @@ FlagDesc flagdesc_mapgen_v5[] = {
|
|||||||
|
|
||||||
|
|
||||||
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||||
: Mapgen(mapgenid, params, emerge)
|
: MapgenBasic(mapgenid, params, emerge)
|
||||||
{
|
{
|
||||||
this->m_emerge = emerge;
|
this->m_emerge = emerge;
|
||||||
this->bmgr = emerge->biomemgr;
|
this->bmgr = emerge->biomemgr;
|
||||||
@ -245,7 +245,7 @@ void MapgenV5::makeChunk(BlockMakeData *data)
|
|||||||
|
|
||||||
// Generate caves
|
// Generate caves
|
||||||
if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
|
if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
|
||||||
generateCaves(stone_surface_max_y);
|
generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
|
||||||
|
|
||||||
// Generate dungeons and desert temples
|
// Generate dungeons and desert temples
|
||||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||||
@ -391,220 +391,3 @@ int MapgenV5::generateBaseTerrain()
|
|||||||
|
|
||||||
return stone_surface_max_y;
|
return stone_surface_max_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MgStoneType MapgenV5::generateBiomes()
|
|
||||||
{
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
MgStoneType stone_type = STONE;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = NULL;
|
|
||||||
u16 depth_top = 0;
|
|
||||||
u16 base_filler = 0;
|
|
||||||
u16 depth_water_top = 0;
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
|
|
||||||
// Check node at base of mapchunk above, either a node of a previously
|
|
||||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
|
||||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
|
||||||
bool air_above = c_above == CONTENT_AIR;
|
|
||||||
bool water_above = c_above == c_water_source;
|
|
||||||
|
|
||||||
// If there is air or water above enable top/filler placement, otherwise force
|
|
||||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
|
||||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
|
||||||
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
// Biome is recalculated each time an upper surface is detected while
|
|
||||||
// working down a column. The selected biome then remains in effect for
|
|
||||||
// all nodes below until the next surface and biome recalculation.
|
|
||||||
// Biome is recalculated:
|
|
||||||
// 1. At the surface of stone below air or water.
|
|
||||||
// 2. At the surface of water below air.
|
|
||||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
|
||||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
|
||||||
(c == c_water_source && (air_above || !biome))) {
|
|
||||||
biome = biomegen->getBiomeAtIndex(index, y);
|
|
||||||
|
|
||||||
depth_top = biome->depth_top;
|
|
||||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
|
||||||
+ noise_filler_depth->result[index], 0);
|
|
||||||
depth_water_top = biome->depth_water_top;
|
|
||||||
|
|
||||||
// Detect stone type for dungeons during every biome calculation.
|
|
||||||
// This is more efficient than detecting per-node and will not
|
|
||||||
// miss any desert stone or sandstone biomes.
|
|
||||||
if (biome->c_stone == c_desert_stone)
|
|
||||||
stone_type = DESERT_STONE;
|
|
||||||
else if (biome->c_stone == c_sandstone)
|
|
||||||
stone_type = SANDSTONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == c_stone) {
|
|
||||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
|
||||||
|
|
||||||
// If the node below isn't solid, make this node stone, so that
|
|
||||||
// any top/filler nodes above are structurally supported.
|
|
||||||
// This is done by aborting the cycle of top/filler placement
|
|
||||||
// immediately by forcing nplaced to stone level.
|
|
||||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
|
||||||
nplaced = U16_MAX;
|
|
||||||
|
|
||||||
if (nplaced < depth_top) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
nplaced++;
|
|
||||||
} else if (nplaced < base_filler) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
|
||||||
nplaced++;
|
|
||||||
} else {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
|
||||||
}
|
|
||||||
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
} else if (c == c_water_source) {
|
|
||||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
|
||||||
biome->c_water_top : biome->c_water);
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = false;
|
|
||||||
water_above = true;
|
|
||||||
} else if (c == CONTENT_AIR) {
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = true;
|
|
||||||
water_above = false;
|
|
||||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
|
||||||
nplaced = U16_MAX; // Disable top/filler placement
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stone_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenV5::dustTopNodes()
|
|
||||||
{
|
|
||||||
if (node_max.Y < water_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
|
||||||
|
|
||||||
if (biome->c_dust == CONTENT_IGNORE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
|
||||||
content_t c_full_max = vm->m_data[vi].getContent();
|
|
||||||
s16 y_start;
|
|
||||||
|
|
||||||
if (c_full_max == CONTENT_AIR) {
|
|
||||||
y_start = full_node_max.Y - 1;
|
|
||||||
} else if (c_full_max == CONTENT_IGNORE) {
|
|
||||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
|
||||||
content_t c_max = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
if (c_max == CONTENT_AIR)
|
|
||||||
y_start = node_max.Y;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi = vm->m_area.index(x, y_start, z);
|
|
||||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
|
||||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
|
||||||
vm->m_area.add_y(em, vi, 1);
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenV5::generateCaves(int max_stone_y)
|
|
||||||
{
|
|
||||||
if (max_stone_y < node_min.Y)
|
|
||||||
return;
|
|
||||||
|
|
||||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index2d = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
|
||||||
bool column_is_open = false; // Is column open to overground
|
|
||||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
|
||||||
// Indexes at column top (node_max.Y)
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
|
||||||
(x - node_min.X);
|
|
||||||
// Biome of column
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
|
||||||
|
|
||||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
|
||||||
// this creates a 'roof' over the tunnel, preventing light in
|
|
||||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
|
||||||
// This 'roof' is removed when the mapchunk above is generated.
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
|
||||||
index3d -= ystride,
|
|
||||||
vm->m_area.add_y(em, vi, -1)) {
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
|
||||||
c == biome->c_water) {
|
|
||||||
column_is_open = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Ground
|
|
||||||
float d1 = contour(noise_cave1->result[index3d]);
|
|
||||||
float d2 = contour(noise_cave2->result[index3d]);
|
|
||||||
|
|
||||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
|
||||||
// In tunnel and ground content, excavate
|
|
||||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
|
||||||
is_tunnel = true;
|
|
||||||
} else {
|
|
||||||
// Not in tunnel or not ground content
|
|
||||||
if (is_tunnel && column_is_open &&
|
|
||||||
(c == biome->c_filler || c == biome->c_stone))
|
|
||||||
// Tunnel entrance floor
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
|
|
||||||
column_is_open = false;
|
|
||||||
is_tunnel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_max.Y > MGV5_LARGE_CAVE_DEPTH)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PseudoRandom ps(blockseed + 21343);
|
|
||||||
u32 bruises_count = ps.range(0, 2);
|
|
||||||
for (u32 i = 0; i < bruises_count; i++) {
|
|
||||||
CaveV5 cave(this, &ps);
|
|
||||||
cave.makeCave(node_min, node_max, max_stone_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -48,34 +48,15 @@ struct MapgenV5Params : public MapgenSpecificParams {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class MapgenV5 : public Mapgen {
|
class MapgenV5 : public MapgenBasic {
|
||||||
public:
|
public:
|
||||||
EmergeManager *m_emerge;
|
|
||||||
BiomeManager *bmgr;
|
|
||||||
|
|
||||||
int ystride;
|
|
||||||
int zstride_1d;
|
|
||||||
|
|
||||||
v3s16 node_min;
|
|
||||||
v3s16 node_max;
|
|
||||||
v3s16 full_node_min;
|
|
||||||
v3s16 full_node_max;
|
|
||||||
|
|
||||||
u32 spflags;
|
u32 spflags;
|
||||||
float cave_width;
|
|
||||||
Noise *noise_filler_depth;
|
|
||||||
Noise *noise_factor;
|
Noise *noise_factor;
|
||||||
Noise *noise_height;
|
Noise *noise_height;
|
||||||
Noise *noise_cave1;
|
|
||||||
Noise *noise_cave2;
|
|
||||||
Noise *noise_ground;
|
Noise *noise_ground;
|
||||||
|
|
||||||
content_t c_stone;
|
|
||||||
content_t c_water_source;
|
|
||||||
content_t c_lava_source;
|
content_t c_lava_source;
|
||||||
content_t c_desert_stone;
|
|
||||||
content_t c_ice;
|
content_t c_ice;
|
||||||
content_t c_sandstone;
|
|
||||||
|
|
||||||
content_t c_cobble;
|
content_t c_cobble;
|
||||||
content_t c_stair_cobble;
|
content_t c_stair_cobble;
|
||||||
@ -90,9 +71,6 @@ public:
|
|||||||
int getSpawnLevelAtPoint(v2s16 p);
|
int getSpawnLevelAtPoint(v2s16 p);
|
||||||
void calculateNoise();
|
void calculateNoise();
|
||||||
int generateBaseTerrain();
|
int generateBaseTerrain();
|
||||||
MgStoneType generateBiomes();
|
|
||||||
void generateCaves(int max_stone_y);
|
|
||||||
void dustTopNodes();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ FlagDesc flagdesc_mapgen_v7[] = {
|
|||||||
|
|
||||||
|
|
||||||
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||||
: Mapgen(mapgenid, params, emerge)
|
: MapgenBasic(mapgenid, params, emerge)
|
||||||
{
|
{
|
||||||
this->m_emerge = emerge;
|
this->m_emerge = emerge;
|
||||||
this->bmgr = emerge->biomemgr;
|
this->bmgr = emerge->biomemgr;
|
||||||
@ -276,7 +276,7 @@ void MapgenV7::makeChunk(BlockMakeData *data)
|
|||||||
MgStoneType stone_type = generateBiomes();
|
MgStoneType stone_type = generateBiomes();
|
||||||
|
|
||||||
if (flags & MG_CAVES)
|
if (flags & MG_CAVES)
|
||||||
generateCaves(stone_surface_max_y);
|
generateCaves(stone_surface_max_y, water_level);
|
||||||
|
|
||||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||||
DungeonParams dp;
|
DungeonParams dp;
|
||||||
@ -517,225 +517,13 @@ void MapgenV7::generateRidgeTerrain()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MgStoneType MapgenV7::generateBiomes()
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
{
|
//// Code Boneyard
|
||||||
v3s16 em = vm->m_area.getExtent();
|
////
|
||||||
u32 index = 0;
|
//// Much of the stuff here has potential to become useful again at some point
|
||||||
MgStoneType stone_type = STONE;
|
//// in the future, but we don't want it to get lost or forgotten in version
|
||||||
|
//// control.
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
////
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = NULL;
|
|
||||||
u16 depth_top = 0;
|
|
||||||
u16 base_filler = 0;
|
|
||||||
u16 depth_water_top = 0;
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
|
|
||||||
// Check node at base of mapchunk above, either a node of a previously
|
|
||||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
|
||||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
|
||||||
bool air_above = c_above == CONTENT_AIR;
|
|
||||||
bool water_above = c_above == c_water_source;
|
|
||||||
|
|
||||||
// If there is air or water above enable top/filler placement, otherwise force
|
|
||||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
|
||||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
|
||||||
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
// Biome is recalculated each time an upper surface is detected while
|
|
||||||
// working down a column. The selected biome then remains in effect for
|
|
||||||
// all nodes below until the next surface and biome recalculation.
|
|
||||||
// Biome is recalculated:
|
|
||||||
// 1. At the surface of stone below air or water.
|
|
||||||
// 2. At the surface of water below air.
|
|
||||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
|
||||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
|
||||||
(c == c_water_source && (air_above || !biome))) {
|
|
||||||
biome = biomegen->getBiomeAtIndex(index, y);
|
|
||||||
|
|
||||||
depth_top = biome->depth_top;
|
|
||||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
|
||||||
+ noise_filler_depth->result[index], 0);
|
|
||||||
depth_water_top = biome->depth_water_top;
|
|
||||||
|
|
||||||
// Detect stone type for dungeons during every biome calculation.
|
|
||||||
// This is more efficient than detecting per-node and will not
|
|
||||||
// miss any desert stone or sandstone biomes.
|
|
||||||
if (biome->c_stone == c_desert_stone)
|
|
||||||
stone_type = DESERT_STONE;
|
|
||||||
else if (biome->c_stone == c_sandstone)
|
|
||||||
stone_type = SANDSTONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == c_stone) {
|
|
||||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
|
||||||
|
|
||||||
// If the node below isn't solid, make this node stone, so that
|
|
||||||
// any top/filler nodes above are structurally supported.
|
|
||||||
// This is done by aborting the cycle of top/filler placement
|
|
||||||
// immediately by forcing nplaced to stone level.
|
|
||||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
|
||||||
nplaced = U16_MAX;
|
|
||||||
|
|
||||||
if (nplaced < depth_top) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
nplaced++;
|
|
||||||
} else if (nplaced < base_filler) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
|
||||||
nplaced++;
|
|
||||||
} else {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
|
||||||
}
|
|
||||||
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
} else if (c == c_water_source) {
|
|
||||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
|
||||||
biome->c_water_top : biome->c_water);
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = false;
|
|
||||||
water_above = true;
|
|
||||||
} else if (c == CONTENT_AIR) {
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = true;
|
|
||||||
water_above = false;
|
|
||||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
|
||||||
nplaced = U16_MAX; // Disable top/filler placement
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stone_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenV7::dustTopNodes()
|
|
||||||
{
|
|
||||||
if (node_max.Y < water_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
|
||||||
|
|
||||||
if (biome->c_dust == CONTENT_IGNORE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
|
||||||
content_t c_full_max = vm->m_data[vi].getContent();
|
|
||||||
s16 y_start;
|
|
||||||
|
|
||||||
if (c_full_max == CONTENT_AIR) {
|
|
||||||
y_start = full_node_max.Y - 1;
|
|
||||||
} else if (c_full_max == CONTENT_IGNORE) {
|
|
||||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
|
||||||
content_t c_max = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
if (c_max == CONTENT_AIR)
|
|
||||||
y_start = node_max.Y;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi = vm->m_area.index(x, y_start, z);
|
|
||||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
|
||||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
|
||||||
vm->m_area.add_y(em, vi, 1);
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenV7::generateCaves(s16 max_stone_y)
|
|
||||||
{
|
|
||||||
if (max_stone_y < node_min.Y)
|
|
||||||
return;
|
|
||||||
|
|
||||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index2d = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
|
||||||
bool column_is_open = false; // Is column open to overground
|
|
||||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
|
||||||
// Indexes at column top (node_max.Y)
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
|
||||||
(x - node_min.X);
|
|
||||||
// Biome of column
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
|
||||||
|
|
||||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
|
||||||
// this creates a 'roof' over the tunnel, preventing light in
|
|
||||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
|
||||||
// This 'roof' is removed when the mapchunk above is generated.
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
|
||||||
index3d -= ystride,
|
|
||||||
vm->m_area.add_y(em, vi, -1)) {
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
|
||||||
c == biome->c_water) {
|
|
||||||
column_is_open = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Ground
|
|
||||||
float d1 = contour(noise_cave1->result[index3d]);
|
|
||||||
float d2 = contour(noise_cave2->result[index3d]);
|
|
||||||
|
|
||||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
|
||||||
// In tunnel and ground content, excavate
|
|
||||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
|
||||||
is_tunnel = true;
|
|
||||||
} else {
|
|
||||||
// Not in tunnel or not ground content
|
|
||||||
if (is_tunnel && column_is_open &&
|
|
||||||
(c == biome->c_filler || c == biome->c_stone))
|
|
||||||
// Tunnel entrance floor
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
|
|
||||||
column_is_open = false;
|
|
||||||
is_tunnel = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_min.Y >= water_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PseudoRandom ps(blockseed + 21343);
|
|
||||||
u32 bruises_count = ps.range(0, 2);
|
|
||||||
for (u32 i = 0; i < bruises_count; i++) {
|
|
||||||
CaveV7 cave(this, &ps);
|
|
||||||
cave.makeCave(node_min, node_max, max_stone_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int MapgenV7::generateMountainTerrain(s16 ymax)
|
int MapgenV7::generateMountainTerrain(s16 ymax)
|
||||||
|
@ -54,42 +54,24 @@ struct MapgenV7Params : public MapgenSpecificParams {
|
|||||||
void writeParams(Settings *settings) const;
|
void writeParams(Settings *settings) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapgenV7 : public Mapgen {
|
class MapgenV7 : public MapgenBasic {
|
||||||
public:
|
public:
|
||||||
EmergeManager *m_emerge;
|
|
||||||
BiomeManager *bmgr;
|
|
||||||
|
|
||||||
int ystride;
|
|
||||||
int zstride_1u1d;
|
int zstride_1u1d;
|
||||||
int zstride_1d;
|
|
||||||
|
|
||||||
v3s16 node_min;
|
|
||||||
v3s16 node_max;
|
|
||||||
v3s16 full_node_min;
|
|
||||||
v3s16 full_node_max;
|
|
||||||
|
|
||||||
s16 *ridge_heightmap;
|
s16 *ridge_heightmap;
|
||||||
|
|
||||||
u32 spflags;
|
u32 spflags;
|
||||||
float cave_width;
|
|
||||||
Noise *noise_terrain_base;
|
Noise *noise_terrain_base;
|
||||||
Noise *noise_terrain_alt;
|
Noise *noise_terrain_alt;
|
||||||
Noise *noise_terrain_persist;
|
Noise *noise_terrain_persist;
|
||||||
Noise *noise_height_select;
|
Noise *noise_height_select;
|
||||||
Noise *noise_filler_depth;
|
|
||||||
Noise *noise_mount_height;
|
Noise *noise_mount_height;
|
||||||
Noise *noise_ridge_uwater;
|
Noise *noise_ridge_uwater;
|
||||||
Noise *noise_mountain;
|
Noise *noise_mountain;
|
||||||
Noise *noise_ridge;
|
Noise *noise_ridge;
|
||||||
Noise *noise_cave1;
|
|
||||||
Noise *noise_cave2;
|
|
||||||
|
|
||||||
content_t c_stone;
|
|
||||||
content_t c_water_source;
|
|
||||||
content_t c_lava_source;
|
content_t c_lava_source;
|
||||||
content_t c_desert_stone;
|
|
||||||
content_t c_ice;
|
content_t c_ice;
|
||||||
content_t c_sandstone;
|
|
||||||
|
|
||||||
content_t c_cobble;
|
content_t c_cobble;
|
||||||
content_t c_stair_cobble;
|
content_t c_stair_cobble;
|
||||||
@ -112,11 +94,6 @@ public:
|
|||||||
|
|
||||||
int generateTerrain();
|
int generateTerrain();
|
||||||
void generateRidgeTerrain();
|
void generateRidgeTerrain();
|
||||||
|
|
||||||
MgStoneType generateBiomes();
|
|
||||||
void dustTopNodes();
|
|
||||||
|
|
||||||
void generateCaves(s16 max_stone_y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MapgenFactoryV7 : public MapgenFactory {
|
struct MapgenFactoryV7 : public MapgenFactory {
|
||||||
|
@ -65,7 +65,7 @@ static FlagDesc flagdesc_mapgen_valleys[] = {
|
|||||||
|
|
||||||
|
|
||||||
MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||||
: Mapgen(mapgenid, params, emerge)
|
: MapgenBasic(mapgenid, params, emerge)
|
||||||
{
|
{
|
||||||
this->m_emerge = emerge;
|
this->m_emerge = emerge;
|
||||||
this->bmgr = emerge->biomemgr;
|
this->bmgr = emerge->biomemgr;
|
||||||
@ -302,7 +302,7 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
|
|||||||
|
|
||||||
// Cave creation.
|
// Cave creation.
|
||||||
if (flags & MG_CAVES)
|
if (flags & MG_CAVES)
|
||||||
generateCaves(stone_surface_max_y);
|
generateCaves(stone_surface_max_y, large_cave_depth);
|
||||||
|
|
||||||
// Dungeon creation
|
// Dungeon creation
|
||||||
if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
|
if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
|
||||||
@ -692,166 +692,7 @@ int MapgenValleys::generateTerrain()
|
|||||||
return surface_max_y;
|
return surface_max_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
|
||||||
MgStoneType MapgenValleys::generateBiomes()
|
|
||||||
{
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
MgStoneType stone_type = STONE;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = NULL;
|
|
||||||
u16 depth_top = 0;
|
|
||||||
u16 base_filler = 0;
|
|
||||||
u16 depth_water_top = 0;
|
|
||||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
|
||||||
|
|
||||||
// Check node at base of mapchunk above, either a node of a previously
|
|
||||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
|
||||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
|
||||||
bool air_above = c_above == CONTENT_AIR;
|
|
||||||
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
|
|
||||||
|
|
||||||
// If there is air or water above enable top/filler placement, otherwise force
|
|
||||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
|
||||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
|
||||||
|
|
||||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
// Biome is recalculated each time an upper surface is detected while
|
|
||||||
// working down a column. The selected biome then remains in effect for
|
|
||||||
// all nodes below until the next surface and biome recalculation.
|
|
||||||
// Biome is recalculated:
|
|
||||||
// 1. At the surface of stone below air or water.
|
|
||||||
// 2. At the surface of water below air.
|
|
||||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
|
||||||
if ((c == c_stone && (air_above || water_above || !biome))
|
|
||||||
|| ((c == c_water_source || c == c_river_water_source)
|
|
||||||
&& (air_above || !biome))) {
|
|
||||||
// Both heat and humidity have already been adjusted for altitude.
|
|
||||||
biome = biomegen->getBiomeAtIndex(index, y);
|
|
||||||
|
|
||||||
depth_top = biome->depth_top;
|
|
||||||
base_filler = MYMAX(depth_top
|
|
||||||
+ biome->depth_filler
|
|
||||||
+ noise_filler_depth->result[index], 0.f);
|
|
||||||
depth_water_top = biome->depth_water_top;
|
|
||||||
|
|
||||||
// Detect stone type for dungeons during every biome calculation.
|
|
||||||
// This is more efficient than detecting per-node and will not
|
|
||||||
// miss any desert stone or sandstone biomes.
|
|
||||||
if (biome->c_stone == c_desert_stone)
|
|
||||||
stone_type = DESERT_STONE;
|
|
||||||
else if (biome->c_stone == c_sandstone)
|
|
||||||
stone_type = SANDSTONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == c_stone) {
|
|
||||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
|
||||||
|
|
||||||
// If the node below isn't solid, make this node stone, so that
|
|
||||||
// any top/filler nodes above are structurally supported.
|
|
||||||
// This is done by aborting the cycle of top/filler placement
|
|
||||||
// immediately by forcing nplaced to stone level.
|
|
||||||
if (c_below == CONTENT_AIR
|
|
||||||
|| c_below == c_water_source
|
|
||||||
|| c_below == c_river_water_source)
|
|
||||||
nplaced = U16_MAX;
|
|
||||||
|
|
||||||
if (nplaced < depth_top) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_top);
|
|
||||||
nplaced++;
|
|
||||||
} else if (nplaced < base_filler) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
|
||||||
nplaced++;
|
|
||||||
} else {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
|
||||||
}
|
|
||||||
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
} else if (c == c_water_source) {
|
|
||||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
|
|
||||||
? biome->c_water_top : biome->c_water);
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = false;
|
|
||||||
water_above = true;
|
|
||||||
} else if (c == c_river_water_source) {
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_river_water);
|
|
||||||
nplaced = depth_top; // Enable filler placement for next surface
|
|
||||||
air_above = false;
|
|
||||||
water_above = true;
|
|
||||||
} else if (c == CONTENT_AIR) {
|
|
||||||
nplaced = 0; // Enable top/filler placement for next surface
|
|
||||||
air_above = true;
|
|
||||||
water_above = false;
|
|
||||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
|
||||||
nplaced = U16_MAX; // Disable top/filler placement
|
|
||||||
air_above = false;
|
|
||||||
water_above = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stone_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenValleys::dustTopNodes()
|
|
||||||
{
|
|
||||||
if (node_max.Y < water_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
|
||||||
u32 index = 0;
|
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
|
||||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
|
||||||
|
|
||||||
if (biome->c_dust == CONTENT_IGNORE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
|
||||||
content_t c_full_max = vm->m_data[vi].getContent();
|
|
||||||
s16 y_start;
|
|
||||||
|
|
||||||
if (c_full_max == CONTENT_AIR) {
|
|
||||||
y_start = full_node_max.Y - 1;
|
|
||||||
} else if (c_full_max == CONTENT_IGNORE) {
|
|
||||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
|
||||||
content_t c_max = vm->m_data[vi].getContent();
|
|
||||||
|
|
||||||
if (c_max == CONTENT_AIR)
|
|
||||||
y_start = node_max.Y;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi = vm->m_area.index(x, y_start, z);
|
|
||||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
|
||||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
|
||||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
|
||||||
vm->m_area.add_y(em, vi, 1);
|
|
||||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapgenValleys::generateCaves(s16 max_stone_y)
|
|
||||||
{
|
{
|
||||||
if (max_stone_y < node_min.Y)
|
if (max_stone_y < node_min.Y)
|
||||||
return;
|
return;
|
||||||
|
@ -85,7 +85,7 @@ struct TerrainNoise {
|
|||||||
float inter_valley_fill;
|
float inter_valley_fill;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapgenValleys : public Mapgen {
|
class MapgenValleys : public MapgenBasic {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||||
@ -97,13 +97,9 @@ public:
|
|||||||
s16 large_cave_depth;
|
s16 large_cave_depth;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EmergeManager *m_emerge;
|
|
||||||
BiomeManager *bmgr;
|
|
||||||
BiomeGenOriginal *m_bgen;
|
BiomeGenOriginal *m_bgen;
|
||||||
|
|
||||||
int ystride;
|
|
||||||
int zstride;
|
int zstride;
|
||||||
int zstride_1d;
|
|
||||||
|
|
||||||
float map_gen_limit;
|
float map_gen_limit;
|
||||||
|
|
||||||
@ -113,11 +109,6 @@ private:
|
|||||||
s16 cave_water_max_height;
|
s16 cave_water_max_height;
|
||||||
s16 lava_max_height;
|
s16 lava_max_height;
|
||||||
|
|
||||||
v3s16 node_min;
|
|
||||||
v3s16 node_max;
|
|
||||||
v3s16 full_node_min;
|
|
||||||
v3s16 full_node_max;
|
|
||||||
|
|
||||||
u32 spflags;
|
u32 spflags;
|
||||||
float altitude_chill;
|
float altitude_chill;
|
||||||
s16 lava_features_lim;
|
s16 lava_features_lim;
|
||||||
@ -126,10 +117,6 @@ private:
|
|||||||
float river_size_factor;
|
float river_size_factor;
|
||||||
float *tcave_cache;
|
float *tcave_cache;
|
||||||
s16 water_features_lim;
|
s16 water_features_lim;
|
||||||
float cave_width;
|
|
||||||
Noise *noise_filler_depth;
|
|
||||||
Noise *noise_cave1;
|
|
||||||
Noise *noise_cave2;
|
|
||||||
Noise *noise_inter_valley_fill;
|
Noise *noise_inter_valley_fill;
|
||||||
Noise *noise_inter_valley_slope;
|
Noise *noise_inter_valley_slope;
|
||||||
Noise *noise_rivers;
|
Noise *noise_rivers;
|
||||||
@ -139,19 +126,13 @@ private:
|
|||||||
Noise *noise_valley_profile;
|
Noise *noise_valley_profile;
|
||||||
|
|
||||||
content_t c_cobble;
|
content_t c_cobble;
|
||||||
content_t c_desert_stone;
|
|
||||||
content_t c_dirt;
|
content_t c_dirt;
|
||||||
content_t c_ice;
|
|
||||||
content_t c_lava_source;
|
content_t c_lava_source;
|
||||||
content_t c_mossycobble;
|
content_t c_mossycobble;
|
||||||
content_t c_river_water_source;
|
|
||||||
content_t c_sand;
|
content_t c_sand;
|
||||||
content_t c_sandstone;
|
|
||||||
content_t c_sandstonebrick;
|
content_t c_sandstonebrick;
|
||||||
content_t c_stair_cobble;
|
content_t c_stair_cobble;
|
||||||
content_t c_stair_sandstonebrick;
|
content_t c_stair_sandstonebrick;
|
||||||
content_t c_stone;
|
|
||||||
content_t c_water_source;
|
|
||||||
|
|
||||||
float terrainLevelAtPoint(s16 x, s16 z);
|
float terrainLevelAtPoint(s16 x, s16 z);
|
||||||
|
|
||||||
@ -161,10 +142,7 @@ private:
|
|||||||
float terrainLevelFromNoise(TerrainNoise *tn);
|
float terrainLevelFromNoise(TerrainNoise *tn);
|
||||||
float adjustedTerrainLevelFromNoise(TerrainNoise *tn);
|
float adjustedTerrainLevelFromNoise(TerrainNoise *tn);
|
||||||
|
|
||||||
MgStoneType generateBiomes();
|
virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
|
||||||
void dustTopNodes();
|
|
||||||
|
|
||||||
void generateCaves(s16 max_stone_y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MapgenFactoryValleys : public MapgenFactory {
|
struct MapgenFactoryValleys : public MapgenFactory {
|
||||||
|
Loading…
Reference in New Issue
Block a user