Skip to content

Commit 3792392

Browse files
authoredAug 7, 2019
Avoid crash caused by, and improve, 'findSpawnPos()' (#8728)
Avoid an unsuitable spawn position (which if outside mapgen limits can cause a crash) if the main 0-3999 loop reaches its end. Fallback to a spawn at 0,0,0. Check the mapgen-returned 'spawn_level' value for being outside limits. When 'air_count' reaches 2, move back down 1 to spawn in the lower empty node. If the spawn position is disallowed by 'objectpos_over_limit()', 'break' from loop instead of 'continue' because positions above are probably also over limit. Reset 'air_count' to 0 if an obstruction is found, to make 'air_count' consecutive empty nodes. Allow spawn in 'airlike' drawtype nodes such as mod-added vacuum, alien atmospheres, fog etc. Add clarifying comments and improve codestyle.
1 parent 0c533dc commit 3792392

File tree

1 file changed

+31
-12
lines changed

1 file changed

+31
-12
lines changed
 

Diff for: ‎src/server.cpp

+31-12
Original file line numberDiff line numberDiff line change
@@ -3512,52 +3512,71 @@ v3f Server::findSpawnPos()
35123512
{
35133513
ServerMap &map = m_env->getServerMap();
35143514
v3f nodeposf;
3515-
if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3515+
if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
35163516
return nodeposf * BS;
3517-
}
35183517

35193518
bool is_good = false;
35203519
// Limit spawn range to mapgen edges (determined by 'mapgen_limit')
35213520
s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
35223521

35233522
// Try to find a good place a few times
3524-
for(s32 i = 0; i < 4000 && !is_good; i++) {
3523+
for (s32 i = 0; i < 4000 && !is_good; i++) {
35253524
s32 range = MYMIN(1 + i, range_max);
35263525
// We're going to try to throw the player to this position
35273526
v2s16 nodepos2d = v2s16(
35283527
-range + (myrand() % (range * 2)),
35293528
-range + (myrand() % (range * 2)));
3530-
35313529
// Get spawn level at point
35323530
s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3533-
// Continue if MAX_MAP_GENERATION_LIMIT was returned by
3534-
// the mapgen to signify an unsuitable spawn position
3535-
if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3531+
// Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3532+
// signify an unsuitable spawn position, or if outside limits.
3533+
if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3534+
spawn_level <= -MAX_MAP_GENERATION_LIMIT)
35363535
continue;
35373536

35383537
v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3539-
3538+
// Consecutive empty nodes
35403539
s32 air_count = 0;
3541-
for (s32 i = 0; i < 10; i++) {
3540+
3541+
// Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3542+
// avoid obstructions in already-generated mapblocks.
3543+
// In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3544+
// no obstructions, but mapgen decorations are generated after spawn so
3545+
// the player may end up inside one.
3546+
for (s32 i = 0; i < 8; i++) {
35423547
v3s16 blockpos = getNodeBlockPos(nodepos);
35433548
map.emergeBlock(blockpos, true);
35443549
content_t c = map.getNodeNoEx(nodepos).getContent();
3545-
if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3550+
3551+
// In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3552+
// In ungenerated mapblocks allow spawn in 'ignore' nodes.
3553+
if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
35463554
air_count++;
35473555
if (air_count >= 2) {
3556+
// Spawn in lower empty node
3557+
nodepos.Y--;
35483558
nodeposf = intToFloat(nodepos, BS);
35493559
// Don't spawn the player outside map boundaries
35503560
if (objectpos_over_limit(nodeposf))
3551-
continue;
3561+
// Exit this loop, positions above are probably over limit
3562+
break;
3563+
3564+
// Good position found, cause an exit from main loop
35523565
is_good = true;
35533566
break;
35543567
}
3568+
} else {
3569+
air_count = 0;
35553570
}
35563571
nodepos.Y++;
35573572
}
35583573
}
35593574

3560-
return nodeposf;
3575+
if (is_good)
3576+
return nodeposf;
3577+
3578+
// No suitable spawn point found, return fallback 0,0,0
3579+
return v3f(0.0f, 0.0f, 0.0f);
35613580
}
35623581

35633582
void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)

0 commit comments

Comments
 (0)
Please sign in to comment.