aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/defaultsettings.cpp1
-rw-r--r--src/emerge.cpp12
-rw-r--r--src/emerge.h1
-rw-r--r--src/mapgen.h7
-rw-r--r--src/mapgen_flat.cpp21
-rw-r--r--src/mapgen_flat.h2
-rw-r--r--src/mapgen_fractal.cpp27
-rw-r--r--src/mapgen_fractal.h2
-rw-r--r--src/mapgen_singlenode.cpp2
-rw-r--r--src/mapgen_singlenode.h2
-rw-r--r--src/mapgen_v5.cpp27
-rw-r--r--src/mapgen_v5.h2
-rw-r--r--src/mapgen_v6.cpp11
-rw-r--r--src/mapgen_v6.h1
-rw-r--r--src/mapgen_v7.cpp22
-rw-r--r--src/mapgen_v7.h2
-rw-r--r--src/mapgen_valleys.cpp35
-rw-r--r--src/mapgen_valleys.h8
-rw-r--r--src/server.cpp16
19 files changed, 123 insertions, 78 deletions
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index ddd7b5fe1..957857976 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -247,7 +247,6 @@ void set_default_settings(Settings *settings)
settings->setDefault("default_privs", "interact, shout");
settings->setDefault("player_transfer_distance", "0");
settings->setDefault("enable_pvp", "true");
- settings->setDefault("vertical_spawn_range", "16");
settings->setDefault("disallow_empty_password", "false");
settings->setDefault("disable_anticheat", "false");
settings->setDefault("enable_rollback_recording", "false");
diff --git a/src/emerge.cpp b/src/emerge.cpp
index ccb4c1703..93e8f2b30 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -334,6 +334,18 @@ v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
}
+int EmergeManager::getSpawnLevelAtPoint(v2s16 p)
+{
+ if (m_mapgens.size() == 0 || !m_mapgens[0]) {
+ errorstream << "EmergeManager: getSpawnLevelAtPoint() called"
+ " before mapgen init" << std::endl;
+ return 0;
+ }
+
+ return m_mapgens[0]->getSpawnLevelAtPoint(p);
+}
+
+
int EmergeManager::getGroundLevelAtPoint(v2s16 p)
{
if (m_mapgens.size() == 0 || !m_mapgens[0]) {
diff --git a/src/emerge.h b/src/emerge.h
index 02bdf7e67..825ac1c0f 100644
--- a/src/emerge.h
+++ b/src/emerge.h
@@ -136,6 +136,7 @@ public:
// Mapgen helpers methods
Biome *getBiomeAtPoint(v3s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
int getGroundLevelAtPoint(v2s16 p);
bool isBlockUnderground(v3s16 blockpos);
diff --git a/src/mapgen.h b/src/mapgen.h
index 9bb7d03b8..abc3d2e89 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -181,6 +181,13 @@ public:
virtual void makeChunk(BlockMakeData *data) {}
virtual int getGroundLevelAtPoint(v2s16 p) { return 0; }
+ // getSpawnLevelAtPoint() is a function within each mapgen that returns a
+ // suitable y co-ordinate for player spawn ('suitable' usually meaning
+ // within 16 nodes of water_level). If a suitable spawn level cannot be
+ // found at the specified (X, Z) 'MAX_MAP_GENERATION_LIMIT' is returned to
+ // signify this and to cause Server::findSpawnPos() to try another (X, Z).
+ virtual int getSpawnLevelAtPoint(v2s16 p) { return 0; }
+
private:
DISABLE_CLASS_COPY(Mapgen);
};
diff --git a/src/mapgen_flat.cpp b/src/mapgen_flat.cpp
index 3b7178dd7..0d071411d 100644
--- a/src/mapgen_flat.cpp
+++ b/src/mapgen_flat.cpp
@@ -192,18 +192,25 @@ void MapgenFlatParams::writeParams(Settings *settings) const
/////////////////////////////////////////////////////////////////
-int MapgenFlat::getGroundLevelAtPoint(v2s16 p)
+int MapgenFlat::getSpawnLevelAtPoint(v2s16 p)
{
+ s16 level_at_point = ground_level;
float n_terrain = NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed);
+
if ((spflags & MGFLAT_LAKES) && n_terrain < lake_threshold) {
- s16 depress = (lake_threshold - n_terrain) * lake_steepness;
- return ground_level - depress;
+ level_at_point = ground_level -
+ (lake_threshold - n_terrain) * lake_steepness;
} else if ((spflags & MGFLAT_HILLS) && n_terrain > hill_threshold) {
- s16 rise = (n_terrain - hill_threshold) * hill_steepness;
- return ground_level + rise;
- } else {
- return ground_level;
+ level_at_point = ground_level +
+ (n_terrain - hill_threshold) * hill_steepness;
}
+
+ if (ground_level < water_level) // Ocean world, allow spawn in water
+ return MYMAX(level_at_point, water_level);
+ else if (level_at_point > water_level)
+ return level_at_point; // Spawn on land
+ else
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
}
diff --git a/src/mapgen_flat.h b/src/mapgen_flat.h
index 0e15df781..282e42975 100644
--- a/src/mapgen_flat.h
+++ b/src/mapgen_flat.h
@@ -102,7 +102,7 @@ public:
~MapgenFlat();
virtual void makeChunk(BlockMakeData *data);
- int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
void calculateNoise();
s16 generateTerrain();
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
diff --git a/src/mapgen_fractal.cpp b/src/mapgen_fractal.cpp
index 9cb682a91..8a5c1e2bc 100644
--- a/src/mapgen_fractal.cpp
+++ b/src/mapgen_fractal.cpp
@@ -209,17 +209,28 @@ void MapgenFractalParams::writeParams(Settings *settings) const
/////////////////////////////////////////////////////////////////
-int MapgenFractal::getGroundLevelAtPoint(v2s16 p)
+int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
{
- s16 search_start = 128;
- s16 search_end = -128;
-
- for (s16 y = search_start; y >= search_end; y--) {
- if (getFractalAtPoint(p.X, y, p.Y))
- return y;
+ bool solid_below = false; // Dry solid node is present below to spawn on
+ u8 air_count = 0; // Consecutive air nodes above the dry solid node
+ s16 seabed_level = NoisePerlin2D(&noise_seabed->np, p.X, p.Y, seed);
+ // Seabed can rise above water_level or might be raised to create dry land
+ s16 search_start = MYMAX(seabed_level, water_level + 1);
+ if (seabed_level > water_level)
+ solid_below = true;
+
+ for (s16 y = search_start; y <= search_start + 128; y++) {
+ if (getFractalAtPoint(p.X, y, p.Y)) { // Fractal node
+ solid_below = true;
+ air_count = 0;
+ } else if (solid_below) { // Air above solid node
+ air_count++;
+ if (air_count == 2)
+ return y - 2;
+ }
}
- return -MAX_MAP_GENERATION_LIMIT;
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
}
diff --git a/src/mapgen_fractal.h b/src/mapgen_fractal.h
index 3d4f7ee8f..ffb2acfb9 100644
--- a/src/mapgen_fractal.h
+++ b/src/mapgen_fractal.h
@@ -114,7 +114,7 @@ public:
~MapgenFractal();
virtual void makeChunk(BlockMakeData *data);
- int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
void calculateNoise();
bool getFractalAtPoint(s16 x, s16 y, s16 z);
s16 generateTerrain();
diff --git a/src/mapgen_singlenode.cpp b/src/mapgen_singlenode.cpp
index f87115269..ff985dd34 100644
--- a/src/mapgen_singlenode.cpp
+++ b/src/mapgen_singlenode.cpp
@@ -99,7 +99,7 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data)
}
-int MapgenSinglenode::getGroundLevelAtPoint(v2s16 p)
+int MapgenSinglenode::getSpawnLevelAtPoint(v2s16 p)
{
return 0;
}
diff --git a/src/mapgen_singlenode.h b/src/mapgen_singlenode.h
index f9c97b508..2c6496c00 100644
--- a/src/mapgen_singlenode.h
+++ b/src/mapgen_singlenode.h
@@ -41,7 +41,7 @@ public:
~MapgenSinglenode();
void makeChunk(BlockMakeData *data);
- int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
};
struct MapgenFactorySinglenode : public MapgenFactory {
diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp
index 06e5f1ca6..0bb3715a8 100644
--- a/src/mapgen_v5.cpp
+++ b/src/mapgen_v5.cpp
@@ -171,7 +171,7 @@ void MapgenV5Params::writeParams(Settings *settings) const
}
-int MapgenV5::getGroundLevelAtPoint(v2s16 p)
+int MapgenV5::getSpawnLevelAtPoint(v2s16 p)
{
//TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO);
@@ -182,24 +182,25 @@ int MapgenV5::getGroundLevelAtPoint(v2s16 p)
f *= 1.6;
float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed);
- s16 search_start = 128; // Only bother searching this range, actual
- s16 search_end = -128; // ground level is rarely higher or lower.
-
- for (s16 y = search_start; y >= search_end; y--) {
+ for (s16 y = 128; y >= -128; y--) {
float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed);
- // If solid
- if (n_ground * f > y - h) {
+
+ if (n_ground * f > y - h) { // If solid
// If either top 2 nodes of search are solid this is inside a
- // mountain or floatland with no space for the player to spawn.
- if (y >= search_start - 1)
- return MAX_MAP_GENERATION_LIMIT;
- else
- return y; // Ground below at least 2 nodes of space
+ // mountain or floatland with possibly no space for the player to spawn.
+ if (y >= 127) {
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+ } else { // Ground below at least 2 nodes of empty space
+ if (y <= water_level || y > water_level + 16)
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+ else
+ return y;
+ }
}
}
//printf("getGroundLevelAtPoint: %dus\n", t.stop());
- return -MAX_MAP_GENERATION_LIMIT;
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn position, no ground found
}
diff --git a/src/mapgen_v5.h b/src/mapgen_v5.h
index 4112bbfa6..44a06907d 100644
--- a/src/mapgen_v5.h
+++ b/src/mapgen_v5.h
@@ -90,7 +90,7 @@ public:
~MapgenV5();
virtual void makeChunk(BlockMakeData *data);
- int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
void calculateNoise();
int generateBaseTerrain();
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index 57d0f59b3..e24083cff 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -318,6 +318,17 @@ int MapgenV6::getGroundLevelAtPoint(v2s16 p)
}
+int MapgenV6::getSpawnLevelAtPoint(v2s16 p)
+{
+ s16 level_at_point = baseTerrainLevelFromNoise(p) + MGV6_AVERAGE_MUD_AMOUNT;
+ if (level_at_point <= water_level ||
+ level_at_point > water_level + 16)
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+ else
+ return level_at_point;
+}
+
+
//////////////////////// Noise functions
float MapgenV6::getMudAmount(v2s16 p)
diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h
index 612e2322a..a55fc6d53 100644
--- a/src/mapgen_v6.h
+++ b/src/mapgen_v6.h
@@ -129,6 +129,7 @@ public:
void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
float baseTerrainLevel(float terrain_base, float terrain_higher,
float steepness, float height_select);
diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp
index aec00b938..029f56a45 100644
--- a/src/mapgen_v7.cpp
+++ b/src/mapgen_v7.cpp
@@ -202,7 +202,7 @@ void MapgenV7Params::writeParams(Settings *settings) const
///////////////////////////////////////
-int MapgenV7::getGroundLevelAtPoint(v2s16 p)
+int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
{
// Base terrain calculation
s16 y = baseTerrainLevelAtPoint(p.X, p.Y);
@@ -210,22 +210,24 @@ int MapgenV7::getGroundLevelAtPoint(v2s16 p)
// Ridge/river terrain calculation
float width = 0.2;
float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2;
- // actually computing the depth of the ridge is much more expensive;
- // if inside a river, simply guess
+ // if inside a river this is an unsuitable spawn point
if (fabs(uwatern) <= width)
- return water_level - 10;
+ return MAX_MAP_GENERATION_LIMIT;
// Mountain terrain calculation
- int iters = 128; // don't even bother iterating more than 128 times..
+ int iters = 128;
while (iters--) {
- //current point would have been air
- if (!getMountainTerrainAtPoint(p.X, y, p.Y))
- return y;
-
+ if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) { // Air, y is ground level
+ if (y <= water_level || y > water_level + 16)
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+ else
+ return y;
+ }
y++;
}
- return y;
+ // Unsuitable spawn point, no ground surface found
+ return MAX_MAP_GENERATION_LIMIT;
}
diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h
index 9b483b041..82f89387b 100644
--- a/src/mapgen_v7.h
+++ b/src/mapgen_v7.h
@@ -103,7 +103,7 @@ public:
~MapgenV7();
virtual void makeChunk(BlockMakeData *data);
- int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
Biome *getBiomeAtPoint(v3s16 p);
float baseTerrainLevelAtPoint(s16 x, s16 z);
diff --git a/src/mapgen_valleys.cpp b/src/mapgen_valleys.cpp
index ceb2c774d..2f96c3397 100644
--- a/src/mapgen_valleys.cpp
+++ b/src/mapgen_valleys.cpp
@@ -56,8 +56,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
//Profiler *mapgen_profiler = &mapgen_prof;
static FlagDesc flagdesc_mapgen_valleys[] = {
- {"altitude_chill", MG_VALLEYS_ALT_CHILL},
- {"humid_rivers", MG_VALLEYS_HUMID_RIVERS},
+ {"altitude_chill", MGVALLEYS_ALT_CHILL},
+ {"humid_rivers", MGVALLEYS_HUMID_RIVERS},
{NULL, 0}
};
@@ -86,8 +86,8 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
this->spflags = sp->spflags;
- this->humid_rivers = (spflags & MG_VALLEYS_HUMID_RIVERS);
- this->use_altitude_chill = (spflags & MG_VALLEYS_ALT_CHILL);
+ this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
+ this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
this->altitude_chill = sp->altitude_chill;
this->humidity_adjust = params->np_biome_humidity.offset - 50.f;
@@ -181,7 +181,7 @@ MapgenValleys::~MapgenValleys()
MapgenValleysParams::MapgenValleysParams()
{
- spflags = MG_VALLEYS_HUMID_RIVERS | MG_VALLEYS_ALT_CHILL;
+ spflags = MGVALLEYS_HUMID_RIVERS | MGVALLEYS_ALT_CHILL;
altitude_chill = 90; // The altitude at which temperature drops by 20C.
large_cave_depth = -33;
@@ -513,24 +513,19 @@ float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
}
-int MapgenValleys::getGroundLevelAtPoint(v2s16 p)
+int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
{
- // ***********************************
- // This method (deliberately) does not
- // return correct terrain values.
- // ***********************************
-
- // Since MT doesn't normally deal with rivers, check
- // to make sure this isn't a request for a location
- // in a river.
+ // Check to make sure this isn't a request for a location in a river.
float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
-
- // If it's wet, return an unusable number.
if (fabs(rivers) < river_size_factor)
- return MAX_MAP_GENERATION_LIMIT;
-
- // Otherwise, return the real result.
- return terrainLevelAtPoint(p.X, p.Y);
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+
+ s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
+ if (level_at_point <= water_level ||
+ level_at_point > water_level + 16)
+ return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
+ else
+ return level_at_point;
}
diff --git a/src/mapgen_valleys.h b/src/mapgen_valleys.h
index ee4052d71..6b3eb9cfe 100644
--- a/src/mapgen_valleys.h
+++ b/src/mapgen_valleys.h
@@ -30,9 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
-/////////////////// Mapgen Valleys flags
-#define MG_VALLEYS_ALT_CHILL 0x01
-#define MG_VALLEYS_HUMID_RIVERS 0x02
+////////////// Mapgen Valleys flags
+#define MGVALLEYS_ALT_CHILL 0x01
+#define MGVALLEYS_HUMID_RIVERS 0x02
// Feed only one variable into these.
#define MYSQUARE(x) (x) * (x)
@@ -96,7 +96,7 @@ public:
~MapgenValleys();
virtual void makeChunk(BlockMakeData *data);
- int getGroundLevelAtPoint(v2s16 p);
+ int getSpawnLevelAtPoint(v2s16 p);
s16 large_cave_depth;
diff --git a/src/server.cpp b/src/server.cpp
index 86096055d..572533146 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -3383,26 +3383,24 @@ v3f Server::findSpawnPos()
return nodeposf * BS;
}
- s16 water_level = map.getWaterLevel();
- s16 vertical_spawn_range = g_settings->getS16("vertical_spawn_range");
bool is_good = false;
// Try to find a good place a few times
- for(s32 i = 0; i < 1000 && !is_good; i++) {
+ for(s32 i = 0; i < 4000 && !is_good; i++) {
s32 range = 1 + i;
// We're going to try to throw the player to this position
v2s16 nodepos2d = v2s16(
-range + (myrand() % (range * 2)),
-range + (myrand() % (range * 2)));
- // Get ground height at point
- s16 groundheight = map.findGroundLevel(nodepos2d);
- // Don't go underwater or to high places
- if (groundheight <= water_level ||
- groundheight > water_level + vertical_spawn_range)
+ // Get spawn level at point
+ s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
+ // Continue if MAX_MAP_GENERATION_LIMIT was returned by
+ // the mapgen to signify an unsuitable spawn position
+ if (spawn_level == MAX_MAP_GENERATION_LIMIT)
continue;
- v3s16 nodepos(nodepos2d.X, groundheight, nodepos2d.Y);
+ v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
s32 air_count = 0;
for (s32 i = 0; i < 10; i++) {