Skip to content

Commit 4adbd69

Browse files
committedFeb 9, 2016
FindSpawnPos: Let mapgens decide what spawn altitude is suitable
To avoid spawn search failing in new specialised mapgens Increase spawn search range to 4000 nodes Add getSpawnLevelAtPoint() functions to EmergeManager, class Mapgen and all mapgens Remove getGroundLevelAtPoint() functions from all mapgens except mgv6 (possibly to be re-added later in the correct form to return actual ground level) Make mgvalleys flag names consistent with other mapgens Remove now unused 'vertical spawn range' setting
1 parent 38e7122 commit 4adbd69

19 files changed

+123
-78
lines changed
 

‎src/defaultsettings.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ void set_default_settings(Settings *settings)
247247
settings->setDefault("default_privs", "interact, shout");
248248
settings->setDefault("player_transfer_distance", "0");
249249
settings->setDefault("enable_pvp", "true");
250-
settings->setDefault("vertical_spawn_range", "16");
251250
settings->setDefault("disallow_empty_password", "false");
252251
settings->setDefault("disable_anticheat", "false");
253252
settings->setDefault("enable_rollback_recording", "false");

‎src/emerge.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,18 @@ v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
334334
}
335335

336336

337+
int EmergeManager::getSpawnLevelAtPoint(v2s16 p)
338+
{
339+
if (m_mapgens.size() == 0 || !m_mapgens[0]) {
340+
errorstream << "EmergeManager: getSpawnLevelAtPoint() called"
341+
" before mapgen init" << std::endl;
342+
return 0;
343+
}
344+
345+
return m_mapgens[0]->getSpawnLevelAtPoint(p);
346+
}
347+
348+
337349
int EmergeManager::getGroundLevelAtPoint(v2s16 p)
338350
{
339351
if (m_mapgens.size() == 0 || !m_mapgens[0]) {

‎src/emerge.h

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class EmergeManager {
136136

137137
// Mapgen helpers methods
138138
Biome *getBiomeAtPoint(v3s16 p);
139+
int getSpawnLevelAtPoint(v2s16 p);
139140
int getGroundLevelAtPoint(v2s16 p);
140141
bool isBlockUnderground(v3s16 blockpos);
141142

‎src/mapgen.h

+7
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ class Mapgen {
181181
virtual void makeChunk(BlockMakeData *data) {}
182182
virtual int getGroundLevelAtPoint(v2s16 p) { return 0; }
183183

184+
// getSpawnLevelAtPoint() is a function within each mapgen that returns a
185+
// suitable y co-ordinate for player spawn ('suitable' usually meaning
186+
// within 16 nodes of water_level). If a suitable spawn level cannot be
187+
// found at the specified (X, Z) 'MAX_MAP_GENERATION_LIMIT' is returned to
188+
// signify this and to cause Server::findSpawnPos() to try another (X, Z).
189+
virtual int getSpawnLevelAtPoint(v2s16 p) { return 0; }
190+
184191
private:
185192
DISABLE_CLASS_COPY(Mapgen);
186193
};

‎src/mapgen_flat.cpp

+14-7
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,25 @@ void MapgenFlatParams::writeParams(Settings *settings) const
192192
/////////////////////////////////////////////////////////////////
193193

194194

195-
int MapgenFlat::getGroundLevelAtPoint(v2s16 p)
195+
int MapgenFlat::getSpawnLevelAtPoint(v2s16 p)
196196
{
197+
s16 level_at_point = ground_level;
197198
float n_terrain = NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed);
199+
198200
if ((spflags & MGFLAT_LAKES) && n_terrain < lake_threshold) {
199-
s16 depress = (lake_threshold - n_terrain) * lake_steepness;
200-
return ground_level - depress;
201+
level_at_point = ground_level -
202+
(lake_threshold - n_terrain) * lake_steepness;
201203
} else if ((spflags & MGFLAT_HILLS) && n_terrain > hill_threshold) {
202-
s16 rise = (n_terrain - hill_threshold) * hill_steepness;
203-
return ground_level + rise;
204-
} else {
205-
return ground_level;
204+
level_at_point = ground_level +
205+
(n_terrain - hill_threshold) * hill_steepness;
206206
}
207+
208+
if (ground_level < water_level) // Ocean world, allow spawn in water
209+
return MYMAX(level_at_point, water_level);
210+
else if (level_at_point > water_level)
211+
return level_at_point; // Spawn on land
212+
else
213+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
207214
}
208215

209216

‎src/mapgen_flat.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class MapgenFlat : public Mapgen {
102102
~MapgenFlat();
103103

104104
virtual void makeChunk(BlockMakeData *data);
105-
int getGroundLevelAtPoint(v2s16 p);
105+
int getSpawnLevelAtPoint(v2s16 p);
106106
void calculateNoise();
107107
s16 generateTerrain();
108108
MgStoneType generateBiomes(float *heat_map, float *humidity_map);

‎src/mapgen_fractal.cpp

+19-8
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,28 @@ void MapgenFractalParams::writeParams(Settings *settings) const
209209
/////////////////////////////////////////////////////////////////
210210

211211

212-
int MapgenFractal::getGroundLevelAtPoint(v2s16 p)
212+
int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
213213
{
214-
s16 search_start = 128;
215-
s16 search_end = -128;
216-
217-
for (s16 y = search_start; y >= search_end; y--) {
218-
if (getFractalAtPoint(p.X, y, p.Y))
219-
return y;
214+
bool solid_below = false; // Dry solid node is present below to spawn on
215+
u8 air_count = 0; // Consecutive air nodes above the dry solid node
216+
s16 seabed_level = NoisePerlin2D(&noise_seabed->np, p.X, p.Y, seed);
217+
// Seabed can rise above water_level or might be raised to create dry land
218+
s16 search_start = MYMAX(seabed_level, water_level + 1);
219+
if (seabed_level > water_level)
220+
solid_below = true;
221+
222+
for (s16 y = search_start; y <= search_start + 128; y++) {
223+
if (getFractalAtPoint(p.X, y, p.Y)) { // Fractal node
224+
solid_below = true;
225+
air_count = 0;
226+
} else if (solid_below) { // Air above solid node
227+
air_count++;
228+
if (air_count == 2)
229+
return y - 2;
230+
}
220231
}
221232

222-
return -MAX_MAP_GENERATION_LIMIT;
233+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
223234
}
224235

225236

‎src/mapgen_fractal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class MapgenFractal : public Mapgen {
114114
~MapgenFractal();
115115

116116
virtual void makeChunk(BlockMakeData *data);
117-
int getGroundLevelAtPoint(v2s16 p);
117+
int getSpawnLevelAtPoint(v2s16 p);
118118
void calculateNoise();
119119
bool getFractalAtPoint(s16 x, s16 y, s16 z);
120120
s16 generateTerrain();

‎src/mapgen_singlenode.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data)
9999
}
100100

101101

102-
int MapgenSinglenode::getGroundLevelAtPoint(v2s16 p)
102+
int MapgenSinglenode::getSpawnLevelAtPoint(v2s16 p)
103103
{
104104
return 0;
105105
}

‎src/mapgen_singlenode.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class MapgenSinglenode : public Mapgen {
4141
~MapgenSinglenode();
4242

4343
void makeChunk(BlockMakeData *data);
44-
int getGroundLevelAtPoint(v2s16 p);
44+
int getSpawnLevelAtPoint(v2s16 p);
4545
};
4646

4747
struct MapgenFactorySinglenode : public MapgenFactory {

‎src/mapgen_v5.cpp

+14-13
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ void MapgenV5Params::writeParams(Settings *settings) const
171171
}
172172

173173

174-
int MapgenV5::getGroundLevelAtPoint(v2s16 p)
174+
int MapgenV5::getSpawnLevelAtPoint(v2s16 p)
175175
{
176176
//TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO);
177177

@@ -182,24 +182,25 @@ int MapgenV5::getGroundLevelAtPoint(v2s16 p)
182182
f *= 1.6;
183183
float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed);
184184

185-
s16 search_start = 128; // Only bother searching this range, actual
186-
s16 search_end = -128; // ground level is rarely higher or lower.
187-
188-
for (s16 y = search_start; y >= search_end; y--) {
185+
for (s16 y = 128; y >= -128; y--) {
189186
float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed);
190-
// If solid
191-
if (n_ground * f > y - h) {
187+
188+
if (n_ground * f > y - h) { // If solid
192189
// If either top 2 nodes of search are solid this is inside a
193-
// mountain or floatland with no space for the player to spawn.
194-
if (y >= search_start - 1)
195-
return MAX_MAP_GENERATION_LIMIT;
196-
else
197-
return y; // Ground below at least 2 nodes of space
190+
// mountain or floatland with possibly no space for the player to spawn.
191+
if (y >= 127) {
192+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
193+
} else { // Ground below at least 2 nodes of empty space
194+
if (y <= water_level || y > water_level + 16)
195+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
196+
else
197+
return y;
198+
}
198199
}
199200
}
200201

201202
//printf("getGroundLevelAtPoint: %dus\n", t.stop());
202-
return -MAX_MAP_GENERATION_LIMIT;
203+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn position, no ground found
203204
}
204205

205206

‎src/mapgen_v5.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class MapgenV5 : public Mapgen {
9090
~MapgenV5();
9191

9292
virtual void makeChunk(BlockMakeData *data);
93-
int getGroundLevelAtPoint(v2s16 p);
93+
int getSpawnLevelAtPoint(v2s16 p);
9494
void calculateNoise();
9595
int generateBaseTerrain();
9696
MgStoneType generateBiomes(float *heat_map, float *humidity_map);

‎src/mapgen_v6.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,17 @@ int MapgenV6::getGroundLevelAtPoint(v2s16 p)
318318
}
319319

320320

321+
int MapgenV6::getSpawnLevelAtPoint(v2s16 p)
322+
{
323+
s16 level_at_point = baseTerrainLevelFromNoise(p) + MGV6_AVERAGE_MUD_AMOUNT;
324+
if (level_at_point <= water_level ||
325+
level_at_point > water_level + 16)
326+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
327+
else
328+
return level_at_point;
329+
}
330+
331+
321332
//////////////////////// Noise functions
322333

323334
float MapgenV6::getMudAmount(v2s16 p)

‎src/mapgen_v6.h

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class MapgenV6 : public Mapgen {
129129

130130
void makeChunk(BlockMakeData *data);
131131
int getGroundLevelAtPoint(v2s16 p);
132+
int getSpawnLevelAtPoint(v2s16 p);
132133

133134
float baseTerrainLevel(float terrain_base, float terrain_higher,
134135
float steepness, float height_select);

‎src/mapgen_v7.cpp

+12-10
Original file line numberDiff line numberDiff line change
@@ -202,30 +202,32 @@ void MapgenV7Params::writeParams(Settings *settings) const
202202
///////////////////////////////////////
203203

204204

205-
int MapgenV7::getGroundLevelAtPoint(v2s16 p)
205+
int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
206206
{
207207
// Base terrain calculation
208208
s16 y = baseTerrainLevelAtPoint(p.X, p.Y);
209209

210210
// Ridge/river terrain calculation
211211
float width = 0.2;
212212
float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2;
213-
// actually computing the depth of the ridge is much more expensive;
214-
// if inside a river, simply guess
213+
// if inside a river this is an unsuitable spawn point
215214
if (fabs(uwatern) <= width)
216-
return water_level - 10;
215+
return MAX_MAP_GENERATION_LIMIT;
217216

218217
// Mountain terrain calculation
219-
int iters = 128; // don't even bother iterating more than 128 times..
218+
int iters = 128;
220219
while (iters--) {
221-
//current point would have been air
222-
if (!getMountainTerrainAtPoint(p.X, y, p.Y))
223-
return y;
224-
220+
if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) { // Air, y is ground level
221+
if (y <= water_level || y > water_level + 16)
222+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
223+
else
224+
return y;
225+
}
225226
y++;
226227
}
227228

228-
return y;
229+
// Unsuitable spawn point, no ground surface found
230+
return MAX_MAP_GENERATION_LIMIT;
229231
}
230232

231233

‎src/mapgen_v7.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class MapgenV7 : public Mapgen {
103103
~MapgenV7();
104104

105105
virtual void makeChunk(BlockMakeData *data);
106-
int getGroundLevelAtPoint(v2s16 p);
106+
int getSpawnLevelAtPoint(v2s16 p);
107107
Biome *getBiomeAtPoint(v3s16 p);
108108

109109
float baseTerrainLevelAtPoint(s16 x, s16 z);

‎src/mapgen_valleys.cpp

+15-20
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
5656
//Profiler *mapgen_profiler = &mapgen_prof;
5757

5858
static FlagDesc flagdesc_mapgen_valleys[] = {
59-
{"altitude_chill", MG_VALLEYS_ALT_CHILL},
60-
{"humid_rivers", MG_VALLEYS_HUMID_RIVERS},
59+
{"altitude_chill", MGVALLEYS_ALT_CHILL},
60+
{"humid_rivers", MGVALLEYS_HUMID_RIVERS},
6161
{NULL, 0}
6262
};
6363

@@ -86,8 +86,8 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
8686
MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
8787
this->spflags = sp->spflags;
8888

89-
this->humid_rivers = (spflags & MG_VALLEYS_HUMID_RIVERS);
90-
this->use_altitude_chill = (spflags & MG_VALLEYS_ALT_CHILL);
89+
this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
90+
this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
9191

9292
this->altitude_chill = sp->altitude_chill;
9393
this->humidity_adjust = params->np_biome_humidity.offset - 50.f;
@@ -181,7 +181,7 @@ MapgenValleys::~MapgenValleys()
181181

182182
MapgenValleysParams::MapgenValleysParams()
183183
{
184-
spflags = MG_VALLEYS_HUMID_RIVERS | MG_VALLEYS_ALT_CHILL;
184+
spflags = MGVALLEYS_HUMID_RIVERS | MGVALLEYS_ALT_CHILL;
185185

186186
altitude_chill = 90; // The altitude at which temperature drops by 20C.
187187
large_cave_depth = -33;
@@ -513,24 +513,19 @@ float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
513513
}
514514

515515

516-
int MapgenValleys::getGroundLevelAtPoint(v2s16 p)
516+
int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
517517
{
518-
// ***********************************
519-
// This method (deliberately) does not
520-
// return correct terrain values.
521-
// ***********************************
522-
523-
// Since MT doesn't normally deal with rivers, check
524-
// to make sure this isn't a request for a location
525-
// in a river.
518+
// Check to make sure this isn't a request for a location in a river.
526519
float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
527-
528-
// If it's wet, return an unusable number.
529520
if (fabs(rivers) < river_size_factor)
530-
return MAX_MAP_GENERATION_LIMIT;
531-
532-
// Otherwise, return the real result.
533-
return terrainLevelAtPoint(p.X, p.Y);
521+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
522+
523+
s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
524+
if (level_at_point <= water_level ||
525+
level_at_point > water_level + 16)
526+
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
527+
else
528+
return level_at_point;
534529
}
535530

536531

‎src/mapgen_valleys.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
3030

3131
#include "mapgen.h"
3232

33-
/////////////////// Mapgen Valleys flags
34-
#define MG_VALLEYS_ALT_CHILL 0x01
35-
#define MG_VALLEYS_HUMID_RIVERS 0x02
33+
////////////// Mapgen Valleys flags
34+
#define MGVALLEYS_ALT_CHILL 0x01
35+
#define MGVALLEYS_HUMID_RIVERS 0x02
3636

3737
// Feed only one variable into these.
3838
#define MYSQUARE(x) (x) * (x)
@@ -96,7 +96,7 @@ class MapgenValleys : public Mapgen {
9696
~MapgenValleys();
9797

9898
virtual void makeChunk(BlockMakeData *data);
99-
int getGroundLevelAtPoint(v2s16 p);
99+
int getSpawnLevelAtPoint(v2s16 p);
100100

101101
s16 large_cave_depth;
102102

0 commit comments

Comments
 (0)
Please sign in to comment.